|  | // Copyright lowRISC contributors. | 
|  | // Licensed under the Apache License, Version 2.0, see LICENSE for details. | 
|  | // SPDX-License-Identifier: Apache-2.0 | 
|  |  | 
|  | /** | 
|  | * This example serves as a starting point for writing software top-level | 
|  | * concurrency tests that use the OpenTitan Test Framework (OTTF), and run at | 
|  | * the flash boot stage. This example is intended to be copied and modified | 
|  | * according to the instructions below. | 
|  | * | 
|  | * This example demonstrates a concurrency test that spawns three FreeRTOS | 
|  | * tasks, in addition to the `test_main` task. Each task is defined using a | 
|  | * separate function that never returns, and deletes itself after executing its | 
|  | * code. Since the priorities of each task are the same, yet higher than the | 
|  | * priority of the "test_main" task, calling `ottf_task_yield()` will switch | 
|  | * control flow between these tasks, until each task deletes itself. Then, the | 
|  | * `test_main` task will continue executing, returning `true` when the overall | 
|  | * test passes, triggering the OTTF to signal test execution has completed. | 
|  | * | 
|  | * Additionally, an example assertion failure is commented out below in `task_3` | 
|  | * to demonstrate how the test will terminate execution immediately upon | 
|  | * encountering said behavior in any task. The test runner (opentitantool) on | 
|  | * Verilator and FPGA platforms is monitoring the UART for a failure message | 
|  | * that gets printed immediately upon an assertion failure. It terminates the | 
|  | * test immediately upon seeing said message. Similarly, in DV, the testbench is | 
|  | * monitoring a specific memory location that gets written to on an assertion | 
|  | * failure. | 
|  | */ | 
|  |  | 
|  | #include "sw/device/lib/runtime/log.h" | 
|  | #include "sw/device/lib/testing/test_framework/check.h" | 
|  | #include "sw/device/lib/testing/test_framework/ottf_macros.h" | 
|  | #include "sw/device/lib/testing/test_framework/ottf_main.h" | 
|  |  | 
|  | OTTF_DEFINE_TEST_CONFIG(.enable_concurrency = true, | 
|  | .can_clobber_uart = false, ); | 
|  |  | 
|  | static void task_1(void *task_parameters) { | 
|  | // *************************************************************************** | 
|  | // Place test code below. | 
|  | // *************************************************************************** | 
|  | LOG_INFO("Executing %s ...", ottf_task_get_self_name()); | 
|  | ottf_task_yield(); | 
|  | LOG_INFO("Continuing to execute %s ...", ottf_task_get_self_name()); | 
|  |  | 
|  | // *************************************************************************** | 
|  | // Delete the current task and never return. | 
|  | // *************************************************************************** | 
|  | OTTF_TASK_DELETE_SELF_OR_DIE; | 
|  | } | 
|  |  | 
|  | static void task_2(void *task_parameters) { | 
|  | // *************************************************************************** | 
|  | // Place test code below. | 
|  | // *************************************************************************** | 
|  | LOG_INFO("Executing %s ...", ottf_task_get_self_name()); | 
|  |  | 
|  | // *************************************************************************** | 
|  | // Delete the current task and never return. | 
|  | // *************************************************************************** | 
|  | OTTF_TASK_DELETE_SELF_OR_DIE; | 
|  | } | 
|  |  | 
|  | static void task_3(void *task_parameters) { | 
|  | // *************************************************************************** | 
|  | // Place test code below. | 
|  | // *************************************************************************** | 
|  | LOG_INFO("Executing %s ...", ottf_task_get_self_name()); | 
|  |  | 
|  | // *************************************************************************** | 
|  | // Uncomment to see the effects of a failed assertion. Delete this when | 
|  | // implementing a test. | 
|  | // *************************************************************************** | 
|  | // CHECK(false, "A failed assertion causes immediate test termination."); | 
|  |  | 
|  | // *************************************************************************** | 
|  | // Delete the current task and never return. | 
|  | // *************************************************************************** | 
|  | OTTF_TASK_DELETE_SELF_OR_DIE; | 
|  | } | 
|  |  | 
|  | bool test_main(void) { | 
|  | // *************************************************************************** | 
|  | // Create the FreeRTOS tasks that will comprise this test. Ensure the priority | 
|  | // levels of each task are higher than the priority of the current "test_main" | 
|  | // task, which is 0. | 
|  | // *************************************************************************** | 
|  | LOG_INFO("Starting to execute %s ...", ottf_task_get_self_name()); | 
|  | CHECK(ottf_task_create(task_1, "task_1", kOttfFreeRtosMinStackSize, 1)); | 
|  | CHECK(ottf_task_create(task_2, "task_2", kOttfFreeRtosMinStackSize, 1)); | 
|  | CHECK(ottf_task_create(task_3, "task_3", kOttfFreeRtosMinStackSize, 1)); | 
|  |  | 
|  | // *************************************************************************** | 
|  | // Yield control flow to the highest priority task in the run queue. Since the | 
|  | // tasks created above all have a higher priority level than the current | 
|  | // "test_main" task, execution will not be returned to the current task until | 
|  | // the above tasks have been deleted. | 
|  | // *************************************************************************** | 
|  | LOG_INFO("Yielding execution to another task."); | 
|  | ottf_task_yield(); | 
|  |  | 
|  | // *************************************************************************** | 
|  | // Return true if the test succeeds. Return false if it should fail. | 
|  | // *************************************************************************** | 
|  | return true; | 
|  | } |