mirror of
https://github.com/espressif/esp-idf.git
synced 2025-08-27 18:32:54 +00:00
Merge branch 'feature/dsp_coprocessor_support' into 'master'
feat(riscv): add support for the DSP coprocessor Closes IDF-13087 and LLVM-369 See merge request espressif/esp-idf!40866
This commit is contained in:
101
components/freertos/test_apps/freertos/port/test_dsp_in_task.c
Normal file
101
components/freertos/test_apps/freertos/port/test_dsp_in_task.c
Normal file
@@ -0,0 +1,101 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include "sdkconfig.h"
|
||||
#include <math.h>
|
||||
#include "soc/soc_caps.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "freertos/semphr.h"
|
||||
#include "unity.h"
|
||||
#include "test_utils.h"
|
||||
|
||||
#if SOC_CPU_HAS_DSP
|
||||
|
||||
#define TEST_NUM_TASKS 4
|
||||
|
||||
typedef struct {
|
||||
int32_t id;
|
||||
uint32_t result;
|
||||
TaskHandle_t main;
|
||||
SemaphoreHandle_t sem;
|
||||
} dsp_params_t;
|
||||
|
||||
/**
|
||||
* @brief Multiplies the given ID by a constant.
|
||||
*
|
||||
* @param id Value to multiply
|
||||
*/
|
||||
uint32_t dsp_id_mul(uint32_t id);
|
||||
|
||||
/**
|
||||
* @brief DSP Assembly routine need to access this constant, make it public.
|
||||
* It will be used as a multiplier.
|
||||
*/
|
||||
const uint32_t g_dsp_constant = 100000;
|
||||
|
||||
static void pinned_task(void *arg)
|
||||
{
|
||||
dsp_params_t *param = (dsp_params_t*) arg;
|
||||
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
|
||||
|
||||
param->result = dsp_id_mul(param->id);
|
||||
|
||||
/* Indicate done and wait to be deleted */
|
||||
xSemaphoreGive((SemaphoreHandle_t)param->sem);
|
||||
vTaskSuspend(NULL);
|
||||
}
|
||||
|
||||
TEST_CASE("DSP: Usage in task", "[freertos]")
|
||||
{
|
||||
TaskHandle_t task_handles[CONFIG_FREERTOS_NUMBER_OF_CORES][TEST_NUM_TASKS];
|
||||
dsp_params_t params[CONFIG_FREERTOS_NUMBER_OF_CORES][TEST_NUM_TASKS];
|
||||
|
||||
SemaphoreHandle_t done_sem = xSemaphoreCreateCounting(TEST_NUM_TASKS, 0);
|
||||
TEST_ASSERT_NOT_EQUAL(NULL, done_sem);
|
||||
|
||||
// Create test tasks for each core
|
||||
for (int i = 0; i < CONFIG_FREERTOS_NUMBER_OF_CORES; i++) {
|
||||
for (int j = 0; j < TEST_NUM_TASKS; j++) {
|
||||
params[i][j] = (dsp_params_t) {
|
||||
.id = i * TEST_NUM_TASKS + j + 1,
|
||||
.sem = done_sem,
|
||||
};
|
||||
TEST_ASSERT_EQUAL(pdTRUE, xTaskCreatePinnedToCore(pinned_task, "task", 4096, (void *) ¶ms[i][j], UNITY_FREERTOS_PRIORITY + 1, &task_handles[i][j], i));
|
||||
}
|
||||
}
|
||||
|
||||
// Start the created tasks
|
||||
for (int i = 0; i < CONFIG_FREERTOS_NUMBER_OF_CORES; i++) {
|
||||
for (int j = 0; j < TEST_NUM_TASKS; j++) {
|
||||
xTaskNotifyGive(task_handles[i][j]);
|
||||
}
|
||||
}
|
||||
|
||||
// Wait for the tasks to complete
|
||||
for (int i = 0; i < CONFIG_FREERTOS_NUMBER_OF_CORES * TEST_NUM_TASKS; i++) {
|
||||
xSemaphoreTake(done_sem, portMAX_DELAY);
|
||||
}
|
||||
|
||||
// Delete the tasks
|
||||
for (int i = 0; i < CONFIG_FREERTOS_NUMBER_OF_CORES; i++) {
|
||||
for (int j = 0; j < TEST_NUM_TASKS; j++) {
|
||||
vTaskDelete(task_handles[i][j]);
|
||||
}
|
||||
}
|
||||
|
||||
// Check the values
|
||||
for (int i = 0; i < CONFIG_FREERTOS_NUMBER_OF_CORES; i++) {
|
||||
for (int j = 0; j < TEST_NUM_TASKS; j++) {
|
||||
dsp_params_t* param = ¶ms[i][j];
|
||||
TEST_ASSERT_EQUAL(param->id * g_dsp_constant, param->result);
|
||||
}
|
||||
}
|
||||
|
||||
vSemaphoreDelete(done_sem);
|
||||
}
|
||||
|
||||
#endif /* SOC_CPU_HAS_DSP */
|
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include "soc/soc_caps.h"
|
||||
|
||||
#if SOC_CPU_HAS_DSP
|
||||
|
||||
#include "riscv/csr_dsp.h"
|
||||
|
||||
/**
|
||||
* @brief Let's allow a small subset of registers to be used in the macro below
|
||||
*/
|
||||
.set regnum_a0, 10
|
||||
.set regnum_a1, 11
|
||||
.set regnum_a2, 12
|
||||
.set regnum_a3, 13
|
||||
.set regnum_a4, 14
|
||||
.set regnum_a5, 15
|
||||
.set regnum_a6, 16
|
||||
.set regnum_a7, 17
|
||||
|
||||
/**
|
||||
* @brief The toolchain doesn't support DSP instructions yet, define it as a constant.
|
||||
*/
|
||||
.macro macs32 _rs1, _rs2
|
||||
.word ( ( regnum_\_rs1 << 15 ) | ( regnum_\_rs2 << 20) | 0b100<<12 | 0b1011011 )
|
||||
.endm
|
||||
|
||||
.global g_dsp_constant
|
||||
|
||||
/**
|
||||
* @brief Multiply the given ID by the global constant defined as g_dsp_constant.
|
||||
* NOTE: The goal of the function is not to be fast and efficient, on the contrary, it needs to be
|
||||
* slow and long so that it will be preempted.
|
||||
*
|
||||
* Parameters:
|
||||
* a0: 32-bit id
|
||||
*
|
||||
* Returns:
|
||||
* a0: multiplied value
|
||||
*/
|
||||
.globl dsp_id_mul
|
||||
dsp_id_mul:
|
||||
csrw 0x809, zero // SAR = 0
|
||||
csrw 0x806, zero // XACC_L
|
||||
csrw 0x807, zero // XACC_H
|
||||
li a1, 1
|
||||
/* Load the constant in a2 */
|
||||
lw a2, (g_dsp_constant)
|
||||
1:
|
||||
// Perform ACC += a0 (=id) * a1 (=1)
|
||||
macs32 a1, a0
|
||||
addi a2, a2, -1
|
||||
bnez a2, 1b
|
||||
// Get the lowest bits
|
||||
csrr a0, 0x806 // XACC_L
|
||||
ret
|
||||
|
||||
|
||||
#endif // SOC_CPU_HAS_DSP
|
Reference in New Issue
Block a user