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:
Omar Chebib
2025-08-08 11:06:22 +08:00
10 changed files with 331 additions and 11 deletions

View 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 *) &params[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 = &params[i][j];
TEST_ASSERT_EQUAL(param->id * g_dsp_constant, param->result);
}
}
vSemaphoreDelete(done_sem);
}
#endif /* SOC_CPU_HAS_DSP */

View File

@@ -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