DSP: add dsp unit test
add dsp context switch test add complex multiplication test for ARC processor Signed-off-by: Siyuan Cheng <siyuanc@synopsys.com>
This commit is contained in:
parent
a147a26a2b
commit
5854670b98
|
@ -125,11 +125,11 @@ dsp_skip_save :
|
||||||
lr r13, [_ARC_V2_AGU_MOD20]
|
lr r13, [_ARC_V2_AGU_MOD20]
|
||||||
st r13, [sp, ___callee_saved_stack_t_agu_mod20_OFFSET]
|
st r13, [sp, ___callee_saved_stack_t_agu_mod20_OFFSET]
|
||||||
lr r13, [_ARC_V2_AGU_MOD21]
|
lr r13, [_ARC_V2_AGU_MOD21]
|
||||||
st r13, [sp, ___callee_saved_stack_t_agu_mod21_OFFSET]
|
_st32_huge_offset r13, sp, ___callee_saved_stack_t_agu_mod21_OFFSET, r1
|
||||||
lr r13, [_ARC_V2_AGU_MOD22]
|
lr r13, [_ARC_V2_AGU_MOD22]
|
||||||
st r13, [sp, ___callee_saved_stack_t_agu_mod22_OFFSET]
|
_st32_huge_offset r13, sp, ___callee_saved_stack_t_agu_mod22_OFFSET, r1
|
||||||
lr r13, [_ARC_V2_AGU_MOD23]
|
lr r13, [_ARC_V2_AGU_MOD23]
|
||||||
st r13, [sp, ___callee_saved_stack_t_agu_mod23_OFFSET]
|
_st32_huge_offset r13, sp, ___callee_saved_stack_t_agu_mod23_OFFSET, r1
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
agu_skip_save :
|
agu_skip_save :
|
||||||
|
@ -254,7 +254,7 @@ dsp_skip_load :
|
||||||
sr r13, [_ARC_V2_AGU_MOD21]
|
sr r13, [_ARC_V2_AGU_MOD21]
|
||||||
ld r13, [sp, ___callee_saved_stack_t_agu_mod22_OFFSET]
|
ld r13, [sp, ___callee_saved_stack_t_agu_mod22_OFFSET]
|
||||||
sr r13, [_ARC_V2_AGU_MOD22]
|
sr r13, [_ARC_V2_AGU_MOD22]
|
||||||
st r13, [sp, ___callee_saved_stack_t_agu_mod23_OFFSET]
|
ld r13, [sp, ___callee_saved_stack_t_agu_mod23_OFFSET]
|
||||||
sr r13, [_ARC_V2_AGU_MOD23]
|
sr r13, [_ARC_V2_AGU_MOD23]
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -4,6 +4,7 @@ type: sim
|
||||||
simulation: nsim
|
simulation: nsim
|
||||||
arch: arc
|
arch: arc
|
||||||
toolchain:
|
toolchain:
|
||||||
|
- zephyr
|
||||||
- arcmwdt
|
- arcmwdt
|
||||||
testing:
|
testing:
|
||||||
ignore_tags:
|
ignore_tags:
|
||||||
|
|
18
tests/arch/arc/arc_dsp_sharing/CMakeLists.txt
Normal file
18
tests/arch/arc/arc_dsp_sharing/CMakeLists.txt
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
# Copyright (c) 2022 Synopsys
|
||||||
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
cmake_minimum_required(VERSION 3.20.0)
|
||||||
|
find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
|
||||||
|
project(dsp_sharing)
|
||||||
|
|
||||||
|
target_sources(app PRIVATE
|
||||||
|
src/main.c
|
||||||
|
src/load_store.c
|
||||||
|
)
|
||||||
|
|
||||||
|
if(COMPILER STREQUAL arcmwdt)
|
||||||
|
zephyr_include_directories(${ARCMWDT_TOOLCHAIN_PATH}/MetaWare/arc/lib/src/fx/include/)
|
||||||
|
target_sources(app PRIVATE src/calculation_arc.c)
|
||||||
|
get_property(Z_ARC_DSP_OPTIONS GLOBAL PROPERTY z_arc_dsp_options)
|
||||||
|
target_compile_options(app PRIVATE ${Z_ARC_DSP_OPTIONS})
|
||||||
|
endif()
|
43
tests/arch/arc/arc_dsp_sharing/README.txt
Normal file
43
tests/arch/arc/arc_dsp_sharing/README.txt
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
Title: Shared DSP Support
|
||||||
|
|
||||||
|
Description:
|
||||||
|
|
||||||
|
This test is only for ARC targets and uses two tasks to:
|
||||||
|
|
||||||
|
1) Test load and store dsp registers (including arch specific registers)
|
||||||
|
2) compute complex vector product and check for any errors
|
||||||
|
|
||||||
|
This tests the ability of tasks to safely share dsp hardware
|
||||||
|
resources, even when switching occurs preemptively (note that both sets of
|
||||||
|
tests run concurrently even though they report their progress at different
|
||||||
|
times).
|
||||||
|
|
||||||
|
The demonstration utilizes semaphores, round robin scheduling, DSP and XY
|
||||||
|
memory support.
|
||||||
|
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
Sample Output:
|
||||||
|
|
||||||
|
Running TESTSUITE dsp_sharing
|
||||||
|
===================================================================
|
||||||
|
START - test_load_store
|
||||||
|
Load and store OK after 0 (high) + 84 (low) tests
|
||||||
|
Load and store OK after 100 (high) + 11926 (low) tests
|
||||||
|
Load and store OK after 200 (high) + 23767 (low) tests
|
||||||
|
Load and store OK after 300 (high) + 35607 (low) tests
|
||||||
|
Load and store OK after 400 (high) + 47448 (low) tests
|
||||||
|
Load and store OK after 500 (high) + 59287 (low) tests
|
||||||
|
PASS - test_load_store in 10.18 seconds
|
||||||
|
===================================================================
|
||||||
|
START - test_calculation
|
||||||
|
complex product calculation OK after 50 (high) + 63297 (low) tests (computed -160)
|
||||||
|
complex product calculation OK after 150 (high) + 188138 (low) tests (computed -160)
|
||||||
|
complex product calculation OK after 250 (high) + 312972 (low) tests (computed -160)
|
||||||
|
complex product calculation OK after 350 (high) + 437806 (low) tests (computed -160)
|
||||||
|
complex product calculation OK after 450 (high) + 562639 (low) tests (computed -160)
|
||||||
|
PASS - test_calculation in 10.16 seconds
|
||||||
|
===================================================================
|
||||||
|
TESTSUITE dsp_sharing succeeded
|
||||||
|
===================================================================
|
||||||
|
PROJECT EXECUTION SUCCESSFUL
|
6
tests/arch/arc/arc_dsp_sharing/prj.conf
Normal file
6
tests/arch/arc/arc_dsp_sharing/prj.conf
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
CONFIG_ZTEST=y
|
||||||
|
CONFIG_ZTEST_NEW_API=y
|
||||||
|
CONFIG_ARC_DSP=y
|
||||||
|
CONFIG_ARC_DSP_SHARING=y
|
||||||
|
CONFIG_MAIN_STACK_SIZE=1024
|
||||||
|
CONFIG_ARC_DSP_BFLY_SHARING=y
|
152
tests/arch/arc/arc_dsp_sharing/src/calculation_arc.c
Normal file
152
tests/arch/arc/arc_dsp_sharing/src/calculation_arc.c
Normal file
|
@ -0,0 +1,152 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2022 Synopsys
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @file
|
||||||
|
* @brief complex number multiplication portion of DSP sharing test
|
||||||
|
*
|
||||||
|
* @ingroup kernel_dspsharing_tests
|
||||||
|
*
|
||||||
|
* This module is used for the DSP sharing test, and supplements the basic
|
||||||
|
* load/store test by incorporating two additional threads that utilize the
|
||||||
|
* DSP unit.
|
||||||
|
*
|
||||||
|
* Testing utilizes a pair of tasks that independently compute complex vector
|
||||||
|
* dot product. The lower priority task is regularly preempted by the higher
|
||||||
|
* priority task, thereby testing whether DSP context information is properly
|
||||||
|
* preserved.
|
||||||
|
*
|
||||||
|
* A reference value of computed result is computed once at the start of the
|
||||||
|
* test. All subsequent computations must produce the same value, otherwise
|
||||||
|
* an error has occurred.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <zephyr/ztest.h>
|
||||||
|
#include "fxarc.h"
|
||||||
|
#include "dsp_context.h"
|
||||||
|
#include "test_common.h"
|
||||||
|
|
||||||
|
/* stored in XY memory, need ARC_AGU_SHARING */
|
||||||
|
#define DATA_ATTR __xy __attribute__((section(".Xdata")))
|
||||||
|
static DATA_ATTR const cq15_t cq15_a[3] = {{0x20, 10}, {0x10, 20}, {4, 30}};
|
||||||
|
static DATA_ATTR const cq15_t cq15_b[3] = {{0x20, 11}, {0x10, 21}, {5, 31}};
|
||||||
|
|
||||||
|
static volatile short reference_result;
|
||||||
|
|
||||||
|
static volatile unsigned int calc_low_count;
|
||||||
|
static volatile unsigned int calc_high_count;
|
||||||
|
|
||||||
|
/* Indicates that the load/store test exited */
|
||||||
|
static volatile bool test_exited;
|
||||||
|
|
||||||
|
/* Semaphore for signaling end of test */
|
||||||
|
static K_SEM_DEFINE(test_exit_sem, 0, 1);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Entry point for the low priority compute task
|
||||||
|
*
|
||||||
|
* @ingroup kernel_dspsharing_tests
|
||||||
|
*/
|
||||||
|
static void calculate_low(void)
|
||||||
|
{
|
||||||
|
volatile short res[2];
|
||||||
|
/* Loop until the test finishes, or an error is detected. */
|
||||||
|
for (calc_low_count = 0; !test_exited; calc_low_count++) {
|
||||||
|
|
||||||
|
v2accum32_t acc = {0, 0};
|
||||||
|
|
||||||
|
for (int i = 0; i < 3; i++) {
|
||||||
|
acc = fx_v2a32_cmac_cq15(acc, cq15_a[i], cq15_b[i]);
|
||||||
|
}
|
||||||
|
/* cast reult from v2accum32_ to short type */
|
||||||
|
res[0] = fx_q15_cast_asl_rnd_a32(fx_get_v2a32(acc, 0), 15);
|
||||||
|
res[1] = fx_q15_cast_asl_rnd_a32(fx_get_v2a32(acc, 1), 15);
|
||||||
|
|
||||||
|
if (reference_result == 0) {
|
||||||
|
reference_result = res[0];
|
||||||
|
} else if (reference_result != res[0]) {
|
||||||
|
printf("Computed result %d, reference result %d\n",
|
||||||
|
res[0], reference_result);
|
||||||
|
}
|
||||||
|
|
||||||
|
zassert_equal(reference_result, res[0], "complex product computation error");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Entry point for the high priority compute task
|
||||||
|
*
|
||||||
|
* @ingroup kernel_dspsharing_tests
|
||||||
|
*/
|
||||||
|
static void calculate_high(void)
|
||||||
|
{
|
||||||
|
volatile short res[2];
|
||||||
|
/* Run the test until the specified maximum test count is reached */
|
||||||
|
for (calc_high_count = 0; calc_high_count <= MAX_TESTS; calc_high_count++) {
|
||||||
|
|
||||||
|
v2accum32_t acc = {0, 0};
|
||||||
|
|
||||||
|
for (int i = 0; i < 3; i++) {
|
||||||
|
acc = fx_v2a32_cmac_cq15(acc, cq15_a[i], cq15_b[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Relinquish the processor for the remainder of the current
|
||||||
|
* system clock tick, so that lower priority threads get a
|
||||||
|
* chance to run.
|
||||||
|
*
|
||||||
|
* This exercises the ability of the kernel to restore the
|
||||||
|
* DSP state of a low priority thread _and_ the ability of the
|
||||||
|
* kernel to provide a "clean" DSP state to this thread
|
||||||
|
* once the sleep ends.
|
||||||
|
*/
|
||||||
|
k_sleep(K_MSEC(10));
|
||||||
|
|
||||||
|
res[0] = fx_q15_cast_asl_rnd_a32(fx_get_v2a32(acc, 0), 15);
|
||||||
|
res[1] = fx_q15_cast_asl_rnd_a32(fx_get_v2a32(acc, 1), 15);
|
||||||
|
|
||||||
|
if (reference_result == 0) {
|
||||||
|
reference_result = res[0];
|
||||||
|
} else if (reference_result != res[0]) {
|
||||||
|
printf("Computed result %d, reference result %d\n",
|
||||||
|
res[0], reference_result);
|
||||||
|
}
|
||||||
|
|
||||||
|
zassert_equal(reference_result, res[0], "complex product computation error");
|
||||||
|
|
||||||
|
/* Periodically issue progress report */
|
||||||
|
if ((calc_high_count % 100) == 50) {
|
||||||
|
printf("complex product calculation OK after %u (high) "
|
||||||
|
"+"
|
||||||
|
" %u (low) tests (computed %d)\n",
|
||||||
|
calc_high_count, calc_low_count, res[0]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Signal end of test */
|
||||||
|
test_exited = true;
|
||||||
|
k_sem_give(&test_exit_sem);
|
||||||
|
}
|
||||||
|
|
||||||
|
K_THREAD_DEFINE(cal_low, THREAD_STACK_SIZE, calculate_low, NULL, NULL, NULL,
|
||||||
|
THREAD_LOW_PRIORITY, THREAD_DSP_FLAGS, K_TICKS_FOREVER);
|
||||||
|
|
||||||
|
K_THREAD_DEFINE(cal_high, THREAD_STACK_SIZE, calculate_high, NULL, NULL, NULL,
|
||||||
|
THREAD_HIGH_PRIORITY, THREAD_DSP_FLAGS, K_TICKS_FOREVER);
|
||||||
|
|
||||||
|
ZTEST(dsp_sharing, test_calculation)
|
||||||
|
{
|
||||||
|
/* Initialise test states */
|
||||||
|
test_exited = false;
|
||||||
|
k_sem_reset(&test_exit_sem);
|
||||||
|
|
||||||
|
/* Start test threads */
|
||||||
|
k_thread_start(cal_low);
|
||||||
|
k_thread_start(cal_high);
|
||||||
|
|
||||||
|
/* Wait for test threads to exit */
|
||||||
|
k_sem_take(&test_exit_sem, K_FOREVER);
|
||||||
|
}
|
50
tests/arch/arc/arc_dsp_sharing/src/dsp_context.h
Normal file
50
tests/arch/arc/arc_dsp_sharing/src/dsp_context.h
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2022 Synopsys
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file
|
||||||
|
* @brief common definitions for the DSP sharing test application
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _DSPCONTEXT_H
|
||||||
|
#define _DSPCONTEXT_H
|
||||||
|
|
||||||
|
struct dsp_volatile_register_set {
|
||||||
|
#ifdef CONFIG_ARC_DSP_BFLY_SHARING
|
||||||
|
uintptr_t dsp_bfly0;
|
||||||
|
#endif
|
||||||
|
#ifdef CONFIG_ARC_AGU_SHARING
|
||||||
|
uintptr_t agu_ap0;
|
||||||
|
uintptr_t agu_os0;
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
struct dsp_non_volatile_register_set {
|
||||||
|
/* No non-volatile dsp registers */
|
||||||
|
};
|
||||||
|
|
||||||
|
#define SIZEOF_DSP_VOLATILE_REGISTER_SET sizeof(struct dsp_volatile_register_set)
|
||||||
|
#define SIZEOF_DSP_NON_VOLATILE_REGISTER_SET 0
|
||||||
|
|
||||||
|
/* the set of ALL dsp registers */
|
||||||
|
|
||||||
|
struct dsp_register_set {
|
||||||
|
struct dsp_volatile_register_set dsp_volatile;
|
||||||
|
struct dsp_non_volatile_register_set dsp_non_volatile;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define SIZEOF_DSP_REGISTER_SET \
|
||||||
|
(SIZEOF_DSP_VOLATILE_REGISTER_SET + SIZEOF_DSP_NON_VOLATILE_REGISTER_SET)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The following constants define the initial byte value used by the background
|
||||||
|
* task, and the thread when loading up the dsp registers.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define MAIN_DSP_REG_CHECK_BYTE ((unsigned char)0xe5)
|
||||||
|
#define FIBER_DSP_REG_CHECK_BYTE ((unsigned char)0xf9)
|
||||||
|
|
||||||
|
#endif /* _DSPCONTEXT_H */
|
81
tests/arch/arc/arc_dsp_sharing/src/dsp_regs_arc.h
Normal file
81
tests/arch/arc/arc_dsp_sharing/src/dsp_regs_arc.h
Normal file
|
@ -0,0 +1,81 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2022, Synopsys.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file
|
||||||
|
* @brief ARC specific dsp register macros
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _DSP_REGS_ARC_H
|
||||||
|
#define _DSP_REGS_ARC_H
|
||||||
|
|
||||||
|
#include <zephyr/toolchain.h>
|
||||||
|
#include "dsp_context.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @brief Load all dsp registers
|
||||||
|
*
|
||||||
|
* This function loads all DSP and AGU registers pointed to by @a regs.
|
||||||
|
* It is expected that a subsequent call to _store_all_dsp_registers()
|
||||||
|
* will be issued to dump the dsp registers to memory.
|
||||||
|
*
|
||||||
|
* The format/organization of 'struct dsp_register_set'; the generic C test
|
||||||
|
* code (main.c) merely treat the register set as an array of bytes.
|
||||||
|
*
|
||||||
|
* The only requirement is that the arch specific implementations of
|
||||||
|
* _load_all_dsp_registers() and _store_all_dsp_registers() agree
|
||||||
|
* on the format.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
void _load_all_dsp_registers(struct dsp_register_set *regs)
|
||||||
|
{
|
||||||
|
uint32_t *temp = (uint32_t *)regs;
|
||||||
|
|
||||||
|
z_arc_v2_aux_reg_write(_ARC_V2_DSP_BFLY0, *temp++);
|
||||||
|
z_arc_v2_aux_reg_write(_ARC_V2_AGU_AP0, *temp++);
|
||||||
|
z_arc_v2_aux_reg_write(_ARC_V2_AGU_OS0, *temp++);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @brief Dump all dsp registers to memory
|
||||||
|
*
|
||||||
|
* This function stores all DSP and AGU registers to the memory buffer
|
||||||
|
* specified by @a regs. It is expected that a previous invocation of
|
||||||
|
* _load_all_dsp_registers() occurred to load all the dsp
|
||||||
|
* registers from a memory buffer.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
void _store_all_dsp_registers(struct dsp_register_set *regs)
|
||||||
|
{
|
||||||
|
uint32_t *temp = (uint32_t *)regs;
|
||||||
|
|
||||||
|
*temp++ = z_arc_v2_aux_reg_read(_ARC_V2_DSP_BFLY0);
|
||||||
|
*temp++ = z_arc_v2_aux_reg_read(_ARC_V2_AGU_AP0);
|
||||||
|
*temp++ = z_arc_v2_aux_reg_read(_ARC_V2_AGU_OS0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @brief Load then dump all dsp registers to memory
|
||||||
|
*
|
||||||
|
* This function loads all DSP and AGU registers from the memory buffer
|
||||||
|
* specified by @a regs, and then stores them back to that buffer.
|
||||||
|
*
|
||||||
|
* This routine is called by a high priority thread prior to calling a primitive
|
||||||
|
* that pends and triggers a co-operative context switch to a low priority
|
||||||
|
* thread.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
void _load_then_store_all_dsp_registers(struct dsp_register_set *regs)
|
||||||
|
{
|
||||||
|
_load_all_dsp_registers(regs);
|
||||||
|
_store_all_dsp_registers(regs);
|
||||||
|
}
|
||||||
|
#endif /* _DSP_REGS_ARC_H */
|
230
tests/arch/arc/arc_dsp_sharing/src/load_store.c
Normal file
230
tests/arch/arc/arc_dsp_sharing/src/load_store.c
Normal file
|
@ -0,0 +1,230 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2022, Synopsys.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @file
|
||||||
|
* @brief load/store portion of DSP sharing test
|
||||||
|
*
|
||||||
|
* @ingroup all_tests
|
||||||
|
*
|
||||||
|
* This module implements the load/store portion of the DSP sharing test. This
|
||||||
|
* version of this test utilizes a pair of tasks.
|
||||||
|
*
|
||||||
|
* The load/store test validates the dsp unit context
|
||||||
|
* save/restore mechanism. This test utilizes a pair of threads of different
|
||||||
|
* priorities that each use the dsp registers. The context
|
||||||
|
* switching that occurs exercises the kernel's ability to properly preserve
|
||||||
|
* the dsp registers. The test also exercises the kernel's ability
|
||||||
|
* to automatically enable dsp support for a task, if supported.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <zephyr/ztest.h>
|
||||||
|
#include <zephyr/debug/gcov.h>
|
||||||
|
#include "dsp_regs_arc.h"
|
||||||
|
#include "dsp_context.h"
|
||||||
|
#include "test_common.h"
|
||||||
|
|
||||||
|
/* space for dsp register load/store area used by low priority task */
|
||||||
|
static struct dsp_register_set dsp_reg_set_load;
|
||||||
|
static struct dsp_register_set dsp_reg_set_store;
|
||||||
|
|
||||||
|
/* space for dsp register load/store area used by high priority thread */
|
||||||
|
static struct dsp_register_set dsp_reg_set;
|
||||||
|
|
||||||
|
static volatile unsigned int load_store_low_count;
|
||||||
|
static volatile unsigned int load_store_high_count;
|
||||||
|
|
||||||
|
/* Indicates that the load/store test exited */
|
||||||
|
static volatile bool test_exited;
|
||||||
|
|
||||||
|
/* Semaphore for signaling end of test */
|
||||||
|
static K_SEM_DEFINE(test_exit_sem, 0, 1);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Low priority DSP load/store thread
|
||||||
|
*
|
||||||
|
* @ingroup kernel_dspsharing_tests
|
||||||
|
*
|
||||||
|
* @see k_sched_time_slice_set(), memset(),
|
||||||
|
* _load_all_dsp_registers(), _store_all_dsp_registers()
|
||||||
|
*/
|
||||||
|
static void load_store_low(void)
|
||||||
|
{
|
||||||
|
volatile unsigned int i;
|
||||||
|
bool error = false;
|
||||||
|
unsigned char init_byte;
|
||||||
|
unsigned char *store_ptr = (unsigned char *)&dsp_reg_set_store;
|
||||||
|
unsigned char *load_ptr = (unsigned char *)&dsp_reg_set_load;
|
||||||
|
/*
|
||||||
|
* Initialize dsp load buffer to known values;
|
||||||
|
* these values must be different than the value used in other threads.
|
||||||
|
*/
|
||||||
|
init_byte = MAIN_DSP_REG_CHECK_BYTE;
|
||||||
|
for (i = 0; i < SIZEOF_DSP_REGISTER_SET; i++) {
|
||||||
|
load_ptr[i] = init_byte++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Loop until the test finishes, or an error is detected. */
|
||||||
|
for (load_store_low_count = 0; !test_exited; load_store_low_count++) {
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Clear store buffer to erase all traces of any previous
|
||||||
|
* dsp values that have been saved.
|
||||||
|
*/
|
||||||
|
(void)memset(&dsp_reg_set_store, 0, SIZEOF_DSP_REGISTER_SET);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Utilize an architecture specific function to load all the
|
||||||
|
* dsp registers with known values.
|
||||||
|
*/
|
||||||
|
_load_all_dsp_registers(&dsp_reg_set_load);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Waste some cycles to give the high priority load/store
|
||||||
|
* thread an opportunity to run when the low priority thread is
|
||||||
|
* using the dsp registers.
|
||||||
|
*
|
||||||
|
* IMPORTANT: This logic requires that sys_clock_tick_get_32() not
|
||||||
|
* perform any dsp operations!
|
||||||
|
*/
|
||||||
|
k_busy_wait(100);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Utilize an architecture specific function to dump the
|
||||||
|
* contents of all dsp registers to memory.
|
||||||
|
*/
|
||||||
|
_store_all_dsp_registers(&dsp_reg_set_store);
|
||||||
|
/*
|
||||||
|
* Compare each byte of buffer to ensure the expected value is
|
||||||
|
* present, indicating that the dsp registers weren't
|
||||||
|
* impacted by the operation of the high priority thread(s).
|
||||||
|
*
|
||||||
|
* Display error message and terminate if discrepancies are
|
||||||
|
* detected.
|
||||||
|
*/
|
||||||
|
init_byte = MAIN_DSP_REG_CHECK_BYTE;
|
||||||
|
|
||||||
|
for (i = 0; i < SIZEOF_DSP_REGISTER_SET; i++) {
|
||||||
|
if (store_ptr[i] != init_byte) {
|
||||||
|
TC_ERROR("Found 0x%x instead of 0x%x @offset 0x%x\n",
|
||||||
|
store_ptr[i], init_byte, i);
|
||||||
|
TC_ERROR("Discrepancy found during iteration %d\n",
|
||||||
|
load_store_low_count);
|
||||||
|
error = true;
|
||||||
|
}
|
||||||
|
init_byte++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Terminate if a test error has been reported */
|
||||||
|
zassert_false(error, NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief High priority DSP load/store thread
|
||||||
|
*
|
||||||
|
* @ingroup kernel_dspsharing_tests
|
||||||
|
*
|
||||||
|
* @see _load_then_store_all_dsp_registers()
|
||||||
|
*/
|
||||||
|
static void load_store_high(void)
|
||||||
|
{
|
||||||
|
volatile unsigned int i;
|
||||||
|
unsigned char init_byte;
|
||||||
|
unsigned char *reg_set_ptr = (unsigned char *)&dsp_reg_set;
|
||||||
|
|
||||||
|
/* Run the test until the specified maximum test count is reached */
|
||||||
|
for (load_store_high_count = 0;
|
||||||
|
load_store_high_count <= MAX_TESTS;
|
||||||
|
load_store_high_count++) {
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Initialize the dsp_reg_set structure by treating it as
|
||||||
|
* a simple array of bytes (the arrangement and actual number
|
||||||
|
* of registers is not important for this generic C code). The
|
||||||
|
* structure is initialized by using the byte value specified
|
||||||
|
* by the constant FIBER_DSP_REG_CHECK_BYTE, and then
|
||||||
|
* incrementing the value for each successive location in the
|
||||||
|
* dsp_reg_set structure.
|
||||||
|
*
|
||||||
|
* The initial byte value, and thus the contents of the entire
|
||||||
|
* dsp_reg_set structure, must be different for each
|
||||||
|
* thread to effectively test the kernel's ability to
|
||||||
|
* properly save/restore the dsp-processed values during a
|
||||||
|
* context switch.
|
||||||
|
*/
|
||||||
|
init_byte = FIBER_DSP_REG_CHECK_BYTE;
|
||||||
|
|
||||||
|
for (i = 0; i < SIZEOF_DSP_REGISTER_SET; i++) {
|
||||||
|
reg_set_ptr[i] = init_byte++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Utilize an architecture specific function to load all the
|
||||||
|
* dsp registers with the contents of the
|
||||||
|
* dsp_reg_set structure.
|
||||||
|
*
|
||||||
|
* The goal of the loading all dsp registers with
|
||||||
|
* values that differ from the values used in other threads is
|
||||||
|
* to help determine whether the dsp register
|
||||||
|
* save/restore mechanism in the kernel's context switcher
|
||||||
|
* is operating correctly.
|
||||||
|
*
|
||||||
|
* When a subsequent k_timer_test() invocation is
|
||||||
|
* performed, a (cooperative) context switch back to the
|
||||||
|
* preempted task will occur. This context switch should result
|
||||||
|
* in restoring the state of the task's dsp
|
||||||
|
* registers when the task was swapped out due to the
|
||||||
|
* occurrence of the timer tick.
|
||||||
|
*/
|
||||||
|
_load_then_store_all_dsp_registers(&dsp_reg_set);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Relinquish the processor for the remainder of the current
|
||||||
|
* system clock tick, so that lower priority threads get a
|
||||||
|
* chance to run.
|
||||||
|
*
|
||||||
|
* This exercises the ability of the kernel to restore the
|
||||||
|
* DSP state of a low priority thread _and_ the ability of the
|
||||||
|
* kernel to provide a "clean" DSP state to this thread
|
||||||
|
* once the sleep ends.
|
||||||
|
*/
|
||||||
|
k_sleep(K_MSEC(1));
|
||||||
|
|
||||||
|
/* Periodically issue progress report */
|
||||||
|
if ((load_store_high_count % 100) == 0) {
|
||||||
|
PRINT_DATA("Load and store OK after %u (high) "
|
||||||
|
"+ %u (low) tests\n",
|
||||||
|
load_store_high_count,
|
||||||
|
load_store_low_count);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Signal end of test */
|
||||||
|
test_exited = true;
|
||||||
|
k_sem_give(&test_exit_sem);
|
||||||
|
}
|
||||||
|
|
||||||
|
K_THREAD_DEFINE(load_low, THREAD_STACK_SIZE, load_store_low, NULL, NULL, NULL,
|
||||||
|
THREAD_LOW_PRIORITY, THREAD_DSP_FLAGS, K_TICKS_FOREVER);
|
||||||
|
|
||||||
|
K_THREAD_DEFINE(load_high, THREAD_STACK_SIZE, load_store_high, NULL, NULL, NULL,
|
||||||
|
THREAD_HIGH_PRIORITY, THREAD_DSP_FLAGS, K_TICKS_FOREVER);
|
||||||
|
|
||||||
|
ZTEST(dsp_sharing, test_load_store)
|
||||||
|
{
|
||||||
|
/* Initialise test states */
|
||||||
|
test_exited = false;
|
||||||
|
k_sem_reset(&test_exit_sem);
|
||||||
|
|
||||||
|
/* Start test threads */
|
||||||
|
k_thread_start(load_low);
|
||||||
|
k_thread_start(load_high);
|
||||||
|
|
||||||
|
/* Wait for test threads to exit */
|
||||||
|
k_sem_take(&test_exit_sem, K_FOREVER);
|
||||||
|
}
|
31
tests/arch/arc/arc_dsp_sharing/src/main.c
Normal file
31
tests/arch/arc/arc_dsp_sharing/src/main.c
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2022 Synopsys
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <zephyr/ztest.h>
|
||||||
|
#include "test_common.h"
|
||||||
|
|
||||||
|
#ifndef CONFIG_ARC_DSP
|
||||||
|
#error Rebuild with the ARC_DSP config option enabled
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef CONFIG_ARC_DSP_SHARING
|
||||||
|
#error Rebuild with the ARC_DSP_SHARING config option enabled
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static void *generic_setup(void)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Enable round robin scheduling to allow both the low priority complex
|
||||||
|
* computation and load/store tasks to execute. The high priority complex
|
||||||
|
* computation and load/store tasks will preempt the low priority tasks
|
||||||
|
* periodically.
|
||||||
|
*/
|
||||||
|
k_sched_time_slice_set(10, THREAD_LOW_PRIORITY);
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
ZTEST_SUITE(dsp_sharing, NULL, generic_setup, NULL, NULL, NULL);
|
17
tests/arch/arc/arc_dsp_sharing/src/test_common.h
Normal file
17
tests/arch/arc/arc_dsp_sharing/src/test_common.h
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2022 Synopsys
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define MAX_TESTS 500
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Test Thread Parameters
|
||||||
|
*/
|
||||||
|
#define THREAD_STACK_SIZE (1024 + CONFIG_TEST_EXTRA_STACK_SIZE)
|
||||||
|
|
||||||
|
#define THREAD_HIGH_PRIORITY 5
|
||||||
|
#define THREAD_LOW_PRIORITY 10
|
||||||
|
|
||||||
|
#define THREAD_DSP_FLAGS (K_ARC_DSP_REGS | K_ARC_AGU_REGS)
|
8
tests/arch/arc/arc_dsp_sharing/testcase.yaml
Normal file
8
tests/arch/arc/arc_dsp_sharing/testcase.yaml
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
tests:
|
||||||
|
dsp_sharing.test_load_store:
|
||||||
|
filter: CONFIG_ISA_ARCV2 and CONFIG_ARC_HAS_DSP
|
||||||
|
platform_allow: nsim_em11d
|
||||||
|
dsp_sharing.test_calculation:
|
||||||
|
filter: CONFIG_ISA_ARCV2 and CONFIG_ARC_HAS_DSP
|
||||||
|
toolchain_allow: arcmwdt
|
||||||
|
platform_allow: nsim_em11d
|
Loading…
Reference in a new issue