| // 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; |
| } |