diff --git a/FreeRTOS/Demo/CORTEX_M3_MPS2_QEMU_GCC/FreeRTOSConfig.h b/FreeRTOS/Demo/CORTEX_M3_MPS2_QEMU_GCC/FreeRTOSConfig.h index f1f72276..e3d72707 100644 --- a/FreeRTOS/Demo/CORTEX_M3_MPS2_QEMU_GCC/FreeRTOSConfig.h +++ b/FreeRTOS/Demo/CORTEX_M3_MPS2_QEMU_GCC/FreeRTOSConfig.h @@ -51,7 +51,7 @@ extern void vAssertCalled( void ); #define configUSE_IDLE_HOOK 1 #define configUSE_TICK_HOOK 1 #define configUSE_DAEMON_TASK_STARTUP_HOOK 0 -#define configCPU_CLOCK_HZ ( ( unsigned long ) 6250000 ) // icount shift 4 // modified +#define configCPU_CLOCK_HZ ( ( unsigned long ) 62500000 ) // icount shift 4 = 62.5 Mips ~= 1/16 GHz #define configTICK_RATE_HZ ( ( TickType_t ) 1000 ) #define configMINIMAL_STACK_SIZE ( ( unsigned short ) 2000 ) #define configTOTAL_HEAP_SIZE ( ( size_t ) ( 900 ) ) diff --git a/FreeRTOS/Demo/CORTEX_M3_MPS2_QEMU_GCC/Makefile b/FreeRTOS/Demo/CORTEX_M3_MPS2_QEMU_GCC/Makefile index 4c10201b..f29bc48c 100644 --- a/FreeRTOS/Demo/CORTEX_M3_MPS2_QEMU_GCC/Makefile +++ b/FreeRTOS/Demo/CORTEX_M3_MPS2_QEMU_GCC/Makefile @@ -123,6 +123,11 @@ ifeq ($(MINIMAL_DEMO), 1) SOURCE_FILES += main_minimal.c CFLAGS := -DmainCREATE_MINIMAL_DEMO=1 +else +ifdef GEN_DEMO + SOURCE_FILES += gen_$(GEN_DEMO).c + + CFLAGS := -DmainCREATE_GEN_DEMO=1 else SOURCE_FILES += main_blinky.c @@ -141,6 +146,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/arbitrary_loads.c b/FreeRTOS/Demo/CORTEX_M3_MPS2_QEMU_GCC/arbitrary_loads.c index 57b8c0b9..cdfd1745 100644 --- a/FreeRTOS/Demo/CORTEX_M3_MPS2_QEMU_GCC/arbitrary_loads.c +++ b/FreeRTOS/Demo/CORTEX_M3_MPS2_QEMU_GCC/arbitrary_loads.c @@ -3,13 +3,15 @@ // Time wasters ===== volatile long _NONSENSE_VAR = 0; -#define NS_PER_INS (1000000000 / configCPU_CLOCK_HZ) // 20MHz +#define NS_PER_INS (1000000000 / configCPU_CLOCK_HZ) #define INS_PER_LOOP 5 // got this multiplier by testing with the goal of getting a 100 ms or 100 tick period #define INS_PER_PRINT 117 // got this multiplier by testing with the goal of getting a 100 ms or 100 tick period, 2 digits #ifndef GLOBAL_WCET_MULT #define GLOBAL_WCET_MULT 1 // Multiplier to increase all waiting periods to make the schedule more tight an force preemptions #endif #define WASTE_TIME(X) for (int i=0; i<=((X*GLOBAL_WCET_MULT)/(NS_PER_INS*INS_PER_LOOP)); i++) {_NONSENSE_VAR+=i;} +#define WASTE_USEC(X) for (int i=0; i<=((X*1000*GLOBAL_WCET_MULT)/(NS_PER_INS*INS_PER_LOOP)); i++) {_NONSENSE_VAR+=i;} +#define WASTE_MSEC(X) for (int i=0; i<=((X*1000000*GLOBAL_WCET_MULT)/(NS_PER_INS*INS_PER_LOOP)); i++) {_NONSENSE_VAR+=i;} #define PRINT_TIME(X,Y) for (int i=0; i<=((X*GLOBAL_WCET_MULT)/((NS_PER_INS*INS_PER_PRINT))); i++) {puts(Y);} // #define PRINT_TIME(X,Y) WASTE_TIME(X) diff --git a/FreeRTOS/Demo/CORTEX_M3_MPS2_QEMU_GCC/gen_3.c b/FreeRTOS/Demo/CORTEX_M3_MPS2_QEMU_GCC/gen_3.c new file mode 100644 index 00000000..bbc55e25 --- /dev/null +++ b/FreeRTOS/Demo/CORTEX_M3_MPS2_QEMU_GCC/gen_3.c @@ -0,0 +1,373 @@ +#include "FreeRTOS.h" +#include "task.h" +#include "semphr.h" + + +/* + +Goal: 500ms + exec period + +feeder > m1 < input 15ms 250ms +machine_1 > shm, sem1 < feeder 30ms 150ms +machine_2 > shm, sem2 < input 30ms 150ms +quality_control > supervisor < sem2 10ms 250ms +supervisor < qc 10ms 250ms +conveyor_belt < sem1, sem2 05ms 150ms +inventory_control > feeder 10ms 50ms +maintenance 10ms 300ms +user_interface 05ms 100ms +system_monitor 10ms 100ms + +target utilization ~95% + + +*/ + +// Task priorities +#define low_TASK_PRIO ( tskIDLE_PRIORITY + 1 ) +#define feeder_TASK_PRIO ( tskIDLE_PRIORITY + 2 ) +#define machine_1_TASK_PRIO ( tskIDLE_PRIORITY + 2 ) +#define machine_2_TASK_PRIO ( tskIDLE_PRIORITY + 3 ) +#define quality_control_TASK_PRIO ( tskIDLE_PRIORITY + 5 ) +#define supervisor_TASK_PRIO ( tskIDLE_PRIORITY + 6 ) +#define conveyor_belt_TASK_PRIO ( tskIDLE_PRIORITY + 7 ) +#define inventory_control_TASK_PRIO ( tskIDLE_PRIORITY + 8 ) +#define maintenance_TASK_PRIO ( tskIDLE_PRIORITY + 9 ) +#define user_interface_TASK_PRIO ( tskIDLE_PRIORITY + 10 ) +#define system_monitor_TASK_PRIO ( tskIDLE_PRIORITY + 11 ) + +// Task handles +TaskHandle_t feeder_task_handle = NULL; +TaskHandle_t machine_1_task_handle = NULL; +TaskHandle_t machine_2_task_handle = NULL; +TaskHandle_t quality_control_task_handle = NULL; +TaskHandle_t supervisor_task_handle = NULL; +TaskHandle_t conveyor_belt_task_handle = NULL; +TaskHandle_t inventory_control_task_handle = NULL; +TaskHandle_t maintenance_task_handle = NULL; +TaskHandle_t user_interface_task_handle = NULL; +TaskHandle_t system_monitor_task_handle = NULL; + +// Semaphores and other synchronization objects +SemaphoreHandle_t machine_1_completion_sem; +SemaphoreHandle_t machine_2_completion_sem; +SemaphoreHandle_t shared_resource_mutex; +static int shared_resource = 0; + +#include +#include "arbitrary_loads.c" + +__attribute__((noinline)) static void trigger_Qemu_break( void ) +{ + puts("Trigger"); + while (1) { + } +} + +// Input Stuff +volatile unsigned int FUZZ_INPUT[2048] = {0xa,0xb,0xc,0xd}; +volatile uint32_t FUZZ_LENGTH = 4; +volatile uint32_t FUZZ_POINTER = 0; +// Read the Byte of Input, if the Input is exausted trigger the breakpoint instead +static unsigned int fuzz_int_next(void) { + // printf("Get next Input from %lx \n",FUZZ_INPUT); + if (FUZZ_POINTER < FUZZ_LENGTH) { + FUZZ_POINTER++; + return FUZZ_INPUT[FUZZ_POINTER-1]; + } else { + // Exausted inputs early + trigger_Qemu_break(); + } +} + +// Worst in 2^24: 15733191 with 704 steps +int collatz(int i) { + int in = i; + int steps = 0; + while (in != 1) { + if (i & 1) {i=i*3+1;} + else {i>=1;} + steps++; + } + return steps; +} + +void feeder_task(void *params) { + TickType_t xLastWakeTime = xTaskGetTickCount(); + while (1) { + // Perform some work here, such as adding materials to the conveyor belt + + int input = fuzz_int_next() & 0xFFFFFF; + int steps = collatz(input); + WASTE_USEC(steps*21); // 701*21 ~= 15ms + + // Put something on the conveyor belt + xTaskNotify(machine_1_task_handle, steps, eSetValueWithOverwrite); + + // Wait for the next activation period + vTaskDelayUntil(&xLastWakeTime, pdMS_TO_TICKS(250)); + } +} + +int SORT_FIELD[4096] = {0}; + +int bubbleSort(int arr[], int n) { + int swaps = 0; + for (int i = 0; i < n - 1; i++) { + for (int j = 0; j < n - i - 1; j++) { + if (arr[j] > arr[j + 1]) { + // Swap arr[j] and arr[j+1] + int temp = arr[j]; + arr[j] = arr[j + 1]; + arr[j + 1] = temp; + swaps++; + } + } + } + return swaps; +} + +void fill_field_rng(int bound) { + SORT_FIELD[0] = RNG_FROM(bound); + for (int i=1; i + +uint32_t popcount(uint32_t x) { + uint32_t count = 0; + while (x != 0) { + count += (x & 1); + x >>= 1; + } + return count; +} + +int complex_function(int input1) { + int result = 0; + for (int i = 0; i < input1; i++) { + if (i % 2 == 0) { + for (int j = 0; j < i*5; j++) { + if (j % 3 == 0) { + for (int k = 0; k < 2*j; k++) { + if (k % 5 == 0) { + int r = RNG_FROM(i ^ j ^ k ); + if ((popcount(r)) > 16) { + result += r; + } + } + } + } + } + } + } + return result; +} + +static int m2_out = 0; +void machine_2_task(void *params) { + TickType_t xLastWakeTime = xTaskGetTickCount(); + while (1) { + // Perform some work here, such as processing materials from machine_1_task + int input = fuzz_int_next(); + int out = complex_function(input); + + out = collatz(out & 0xFFFFFF); + WASTE_USEC(out*100); + m2_out = out; + + // Signal completion using a binary semaphore + xSemaphoreGive(machine_2_completion_sem); + + // Wait for access to a shared resource using a mutex + xSemaphoreTake(shared_resource_mutex, portMAX_DELAY); + + // Perform some more work here + shared_resource = small_increase_slow(shared_resource); + + // Release the mutex + xSemaphoreGive(shared_resource_mutex); + + // Wait for the next activation period + vTaskDelayUntil(&xLastWakeTime, pdMS_TO_TICKS(150)); + } +} + +void quality_control_task(void *params) { + TickType_t xLastWakeTime = xTaskGetTickCount(); + while (1) { + // Perform some work here, such as checking the quality of materials from machine_2_task + int waited = xSemaphoreTake(machine_2_completion_sem, 3); + if (waited == pdFALSE) { + WASTE_MSEC(10); + } else { + WASTE_MSEC(5); + if (m2_out & 1) { /* defect detected */ + // Send a notification to the supervisor task + xTaskNotifyFromISR(supervisor_task_handle, 0, eNoAction, NULL); + } + xSemaphoreGive(machine_2_completion_sem); + } + + // Wait for the next activation period + vTaskDelayUntil(&xLastWakeTime, pdMS_TO_TICKS(250)); + } +} + +void supervisor_task(void *params) { + TickType_t xLastWakeTime = xTaskGetTickCount(); + while (1) { + // Perform some work here, such as monitoring the status of all machines + + // Wait for notifications from other tasks + int result = ulTaskNotifyTake(pdFALSE, pdMS_TO_TICKS(50)); + + // Take corrective action if any issues are detected + if (result == pdTRUE) { + WASTE_MSEC(10); + } else { + WASTE_MSEC(5); + } + + // Wait for the next activation period + vTaskDelayUntil(&xLastWakeTime, pdMS_TO_TICKS(250)); + } +} + +void conveyor_belt_task(void *params) { + TickType_t xLastWakeTime = xTaskGetTickCount(); + while (1) { + // Perform some work here, such as controlling the movement of materials through the assembly line + + // Wait for signals from other tasks using binary semaphores + xSemaphoreTake(machine_1_completion_sem, portMAX_DELAY); + xSemaphoreTake(machine_2_completion_sem, portMAX_DELAY); + + // Adjust speed based on the signals received + WASTE_MSEC(5); + + // Wait for the next activation period + vTaskDelayUntil(&xLastWakeTime, pdMS_TO_TICKS(100)); + } +} + +void inventory_control_task(void *params) { + TickType_t xLastWakeTime = xTaskGetTickCount(); + while (1) { + // Perform some work here, such as keeping track of inventory levels + + if (1) { /* more materials needed */ + // Send a notification to the feeder task + WASTE_MSEC(10); + xTaskNotifyFromISR(feeder_task_handle, 0, eNoAction, NULL); + } + + // Wait for the next activation period + vTaskDelayUntil(&xLastWakeTime, pdMS_TO_TICKS(50)); + } +} + +void maintenance_task(void *params) { + TickType_t xLastWakeTime = xTaskGetTickCount(); + while (1) { + // Perform some work here, such as performing periodic maintenance operations on the machines + WASTE_MSEC(10); + + // Wait for the next activation period + vTaskDelayUntil(&xLastWakeTime, pdMS_TO_TICKS(300)); + } +} + +void user_interface_task(void *params) { + TickType_t xLastWakeTime = xTaskGetTickCount(); + while (1) { + // Perform some work here, such as providing a user interface for controlling the system and displaying status information + + // Wait for updates from other tasks using binary semaphores or task notifications + + // Update the UI with new data + WASTE_MSEC(5); + + // Wait for the next activation period + vTaskDelayUntil(&xLastWakeTime, pdMS_TO_TICKS(100)); + } +} + +void system_monitor_task(void *params) { + TickType_t xLastWakeTime = xTaskGetTickCount(); + while (1) { + // Perform some work here, such as monitoring the health of the system and sending notifications if any issues are detected + WASTE_MSEC(10); + + // Wait for the next activation period + vTaskDelayUntil(&xLastWakeTime, pdMS_TO_TICKS(100)); + } +} + +void main_gen(void) { + // Initialize synchronization objects + machine_1_completion_sem = xSemaphoreCreateBinary(); + machine_2_completion_sem = xSemaphoreCreateBinary(); + shared_resource_mutex = xSemaphoreCreateMutex(); + + // Create tasks + xTaskCreate(feeder_task, "feeder", configMINIMAL_STACK_SIZE, NULL, feeder_TASK_PRIO, &feeder_task_handle); + xTaskCreate(machine_1_task, "machine_1", configMINIMAL_STACK_SIZE, NULL, machine_1_TASK_PRIO, &machine_1_task_handle); + xTaskCreate(machine_2_task, "machine_2", configMINIMAL_STACK_SIZE, NULL, machine_2_TASK_PRIO, &machine_2_task_handle); + xTaskCreate(quality_control_task, "quality_control", configMINIMAL_STACK_SIZE, NULL, quality_control_TASK_PRIO, &quality_control_task_handle); + xTaskCreate(supervisor_task, "supervisor", configMINIMAL_STACK_SIZE, NULL, supervisor_TASK_PRIO, &supervisor_task_handle); + xTaskCreate(conveyor_belt_task, "conveyor_belt", configMINIMAL_STACK_SIZE, NULL, conveyor_belt_TASK_PRIO, &conveyor_belt_task_handle); + xTaskCreate(inventory_control_task, "inventory_control", configMINIMAL_STACK_SIZE, NULL, inventory_control_TASK_PRIO, &inventory_control_task_handle); + xTaskCreate(maintenance_task, "maintenance", configMINIMAL_STACK_SIZE, NULL, maintenance_TASK_PRIO, &maintenance_task_handle); + xTaskCreate(user_interface_task, "user_interface", configMINIMAL_STACK_SIZE, NULL, user_interface_TASK_PRIO, &user_interface_task_handle); + xTaskCreate(system_monitor_task, "system_monitor", configMINIMAL_STACK_SIZE, NULL, system_monitor_TASK_PRIO, &system_monitor_task_handle); + + vTaskStartScheduler(); + trigger_Qemu_break(); +} + +void isr_starter( void ) +{ +} \ No newline at end of file diff --git a/FreeRTOS/Demo/CORTEX_M3_MPS2_QEMU_GCC/main.c b/FreeRTOS/Demo/CORTEX_M3_MPS2_QEMU_GCC/main.c index d61dcc6a..77017810 100644 --- a/FreeRTOS/Demo/CORTEX_M3_MPS2_QEMU_GCC/main.c +++ b/FreeRTOS/Demo/CORTEX_M3_MPS2_QEMU_GCC/main.c @@ -107,6 +107,10 @@ int main() { main_minimal(); } + #elif ( mainCREATE_GEN_DEMO == 1 ) + { + main_gen(); + } #else {