mirror of
https://github.com/espressif/esp-idf.git
synced 2025-08-29 05:38:42 +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:
@@ -136,7 +136,11 @@ BaseType_t xPortStartScheduler(void)
|
||||
#if SOC_CPU_HAS_PIE
|
||||
/* Similarly, disable PIE */
|
||||
rv_utils_disable_pie();
|
||||
#endif /* SOC_CPU_HAS_FPU */
|
||||
#endif /* SOC_CPU_HAS_PIE */
|
||||
|
||||
#if SOC_CPU_HAS_DSP
|
||||
rv_utils_disable_dsp();
|
||||
#endif /* SOC_CPU_HAS_DSP */
|
||||
|
||||
#if SOC_CPU_HAS_HWLOOP
|
||||
/* Initialize the Hardware loop feature */
|
||||
|
@@ -10,6 +10,7 @@
|
||||
#include "riscv/rvruntime-frames.h"
|
||||
#include "riscv/csr_hwlp.h"
|
||||
#include "riscv/csr_pie.h"
|
||||
#include "riscv/csr_dsp.h"
|
||||
|
||||
.extern pxCurrentTCBs
|
||||
|
||||
@@ -329,6 +330,59 @@ generate_coprocessor_routine pie, PIE_COPROC_IDX, pie_enable, pie_save_regs, pie
|
||||
#endif /* SOC_CPU_HAS_PIE */
|
||||
|
||||
|
||||
#if SOC_CPU_HAS_DSP
|
||||
|
||||
/**
|
||||
* @brief Macros to enable and disable the DSP coprocessor on the current core
|
||||
*/
|
||||
.macro dsp_enable scratch_reg=a0
|
||||
li \scratch_reg, 1
|
||||
csrw CSR_DSP_STATE_REG, \scratch_reg
|
||||
.endm
|
||||
|
||||
/**
|
||||
* @brief Disable the DSP coprocessor while returning the former status in the given register
|
||||
*/
|
||||
.macro dsp_disable reg
|
||||
csrrw \reg, CSR_DSP_STATE_REG, zero
|
||||
/* Only keep the lowest two bits, if register is 0, DSP was off */
|
||||
andi \reg, \reg, 0b11
|
||||
beqz \reg, 1f
|
||||
/* It was ON, return the enable bit in \reg */
|
||||
li \reg, 1 << DSP_COPROC_IDX
|
||||
1:
|
||||
.endm
|
||||
|
||||
/**
|
||||
* @brief Macros to save and restore the DSP coprocessor registers to and from the given frame
|
||||
*/
|
||||
.macro dsp_save_regs frame=a0
|
||||
csrr a1, CSR_DSP_XACC_L
|
||||
sw a1, RV_DSP_XACC_L(\frame)
|
||||
csrr a1, CSR_DSP_XACC_H
|
||||
sw a1, RV_DSP_XACC_H(\frame)
|
||||
csrr a1, CSR_DSP_SAR
|
||||
sw a1, RV_DSP_SAR(\frame)
|
||||
csrr a1, CSR_DSP_STATUS
|
||||
sw a1, RV_DSP_STATUS(\frame)
|
||||
.endm
|
||||
|
||||
|
||||
.macro dsp_restore_regs frame=a0
|
||||
lw a1, RV_DSP_XACC_L(\frame)
|
||||
csrw CSR_DSP_XACC_L, a1
|
||||
lw a1, RV_DSP_XACC_H(\frame)
|
||||
csrw CSR_DSP_XACC_H, a1
|
||||
lw a1, RV_DSP_SAR(\frame)
|
||||
csrw CSR_DSP_SAR, a1
|
||||
lw a1, RV_DSP_STATUS(\frame)
|
||||
csrw CSR_DSP_STATUS, a1
|
||||
.endm
|
||||
|
||||
generate_coprocessor_routine dsp, DSP_COPROC_IDX, dsp_enable, dsp_save_regs, dsp_restore_regs
|
||||
|
||||
#endif /* SOC_CPU_HAS_DSP */
|
||||
|
||||
#if SOC_CPU_HAS_FPU
|
||||
|
||||
/* Bit to set in mstatus to enable the FPU */
|
||||
@@ -513,6 +567,12 @@ rtos_int_enter:
|
||||
or s2, s2, a0
|
||||
#endif /* SOC_CPU_HAS_PIE */
|
||||
|
||||
#if SOC_CPU_HAS_DSP
|
||||
/* The current DSP coprocessor status will be returned in a0 */
|
||||
dsp_disable a0
|
||||
or s2, s2, a0
|
||||
#endif /* SOC_CPU_HAS_DSP */
|
||||
|
||||
#if SOC_CPU_HAS_FPU
|
||||
fpu_disable a0
|
||||
#endif /* SOC_CPU_HAS_FPU */
|
||||
@@ -675,6 +735,14 @@ no_context_switch:
|
||||
pie_enable a1
|
||||
1:
|
||||
#endif /* SOC_CPU_HAS_PIE */
|
||||
|
||||
#if SOC_CPU_HAS_DSP
|
||||
/* Re-enable the DSP coprocessor if it was used */
|
||||
andi a1, s8, 1 << DSP_COPROC_IDX
|
||||
beqz a1, 1f
|
||||
dsp_enable a1
|
||||
1:
|
||||
#endif /* SOC_CPU_HAS_DSP */
|
||||
j restore_stack_pointer
|
||||
|
||||
context_switch_requested:
|
||||
|
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
|
27
components/riscv/include/riscv/csr_dsp.h
Normal file
27
components/riscv/include/riscv/csr_dsp.h
Normal file
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "soc/soc_caps.h"
|
||||
|
||||
#if SOC_CPU_HAS_DSP
|
||||
|
||||
#define CSR_DSP_XACC_L 0x806
|
||||
#define CSR_DSP_XACC_H 0x807
|
||||
#define CSR_DSP_SAR 0x809
|
||||
#define CSR_DSP_STATUS 0x80a
|
||||
|
||||
/**
|
||||
* CSR lowest 2 bits describe the following states:
|
||||
* 00: Off
|
||||
* 01: Initial
|
||||
* 10: Clean
|
||||
* 11: Dirty
|
||||
*/
|
||||
#define CSR_DSP_STATE_REG 0x7f3
|
||||
|
||||
#endif /* SOC_CPU_HAS_DSP */
|
@@ -14,6 +14,7 @@
|
||||
#include "riscv/csr.h"
|
||||
#include "riscv/interrupt.h"
|
||||
#include "riscv/csr_pie.h"
|
||||
#include "riscv/csr_dsp.h"
|
||||
#include "sdkconfig.h"
|
||||
|
||||
#if CONFIG_SECURE_ENABLE_TEE && !NON_OS_BUILD
|
||||
@@ -275,7 +276,27 @@ FORCE_INLINE_ATTR void rv_utils_disable_pie(void)
|
||||
RV_WRITE_CSR(CSR_PIE_STATE_REG, 0);
|
||||
}
|
||||
|
||||
#endif /* SOC_CPU_HAS_FPU */
|
||||
#endif /* SOC_CPU_HAS_PIE */
|
||||
|
||||
|
||||
/* ------------------------------------------------- DSP Related ----------------------------------------------------
|
||||
*
|
||||
* ------------------------------------------------------------------------------------------------------------------ */
|
||||
|
||||
#if SOC_CPU_HAS_DSP
|
||||
|
||||
FORCE_INLINE_ATTR void rv_utils_enable_dsp(void)
|
||||
{
|
||||
RV_WRITE_CSR(CSR_DSP_STATE_REG, 1);
|
||||
}
|
||||
|
||||
|
||||
FORCE_INLINE_ATTR void rv_utils_disable_dsp(void)
|
||||
{
|
||||
RV_WRITE_CSR(CSR_DSP_STATE_REG, 0);
|
||||
}
|
||||
|
||||
#endif /* SOC_CPU_HAS_DSP */
|
||||
|
||||
|
||||
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
@@ -179,6 +179,36 @@ STRUCT_END(RvHWLPSaveArea)
|
||||
#endif /* SOC_CPU_HAS_HWLOOP */
|
||||
|
||||
|
||||
#if SOC_CPU_HAS_DSP
|
||||
|
||||
/* DSP coprocessor is considered coprocessor 1, just like the HWLP, make sure both are not present on the same target */
|
||||
#define DSP_COPROC_IDX 1
|
||||
|
||||
#ifdef SOC_CPU_HAS_HWLOOP
|
||||
#error "HWLP and DSP share the same coprocessor index!"
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief DSP save area
|
||||
*/
|
||||
STRUCT_BEGIN
|
||||
STRUCT_FIELD (long, 4, RV_DSP_XACC_L, xacc_l)
|
||||
STRUCT_FIELD (long, 4, RV_DSP_XACC_H, xacc_h)
|
||||
STRUCT_FIELD (long, 4, RV_DSP_SAR, sar)
|
||||
STRUCT_FIELD (long, 4, RV_DSP_STATUS, status)
|
||||
STRUCT_END(RvDSPSaveArea)
|
||||
|
||||
/* Redefine the coprocessor area size previously defined to 0 */
|
||||
#undef RV_COPROC1_SIZE
|
||||
|
||||
#if defined(_ASMLANGUAGE) || defined(__ASSEMBLER__)
|
||||
#define RV_COPROC1_SIZE RvDSPSaveAreaSize
|
||||
#else
|
||||
#define RV_COPROC1_SIZE sizeof(RvDSPSaveArea)
|
||||
#endif /* defined(_ASMLANGUAGE) || defined(__ASSEMBLER__) */
|
||||
|
||||
#endif /* SOC_CPU_HAS_DSP */
|
||||
|
||||
|
||||
#if SOC_CPU_HAS_PIE
|
||||
|
||||
|
@@ -20,22 +20,18 @@
|
||||
|
||||
#if ( SOC_CPU_COPROC_NUM > 0 )
|
||||
/* Targets with coprocessors present a special CSR to get Illegal Instruction exception reason */
|
||||
#ifdef __clang__
|
||||
/* Clang does not support constant declared via `equ` as operand for csrrw
|
||||
* TODO: LLVM-369
|
||||
*/
|
||||
#define EXT_ILL_CSR 0x7F0
|
||||
#else
|
||||
.equ EXT_ILL_CSR, 0x7F0
|
||||
#endif
|
||||
|
||||
/* EXT_ILL CSR reasons are stored as follows:
|
||||
* - Bit 0: FPU core instruction (Load/Store instructions NOT concerned)
|
||||
* - Bit 1: Hardware Loop instructions
|
||||
* - Bit 2: PIE core */
|
||||
* - Bit 2: PIE core
|
||||
* - Bit 3: DSP core
|
||||
*/
|
||||
.equ EXT_ILL_RSN_FPU, 1
|
||||
.equ EXT_ILL_RSN_HWLP, 2
|
||||
.equ EXT_ILL_RSN_PIE, 4
|
||||
.equ EXT_ILL_RSN_DSP, 8
|
||||
#endif /* SOC_CPU_COPROC_NUM > 0 */
|
||||
|
||||
/* Macro which first allocates space on the stack to save general
|
||||
@@ -252,6 +248,12 @@ _panic_handler:
|
||||
bnez a1, rtos_save_pie_coproc
|
||||
#endif /* SOC_CPU_HAS_PIE */
|
||||
|
||||
#if SOC_CPU_HAS_DSP
|
||||
/* Check if the DSP bit is set. */
|
||||
andi a1, a0, EXT_ILL_RSN_DSP
|
||||
bnez a1, rtos_save_dsp_coproc
|
||||
#endif /* SOC_CPU_HAS_DSP */
|
||||
|
||||
/* We cannot check the HWLP bit in a0 since a hardware bug may set this bit even though no HWLP
|
||||
* instruction was executed in the program at all, so check mtval (`t0`) */
|
||||
#if SOC_CPU_HAS_HWLOOP
|
||||
|
@@ -183,6 +183,10 @@ config SOC_CPU_HAS_FPU_EXT_ILL_BUG
|
||||
bool
|
||||
default n
|
||||
|
||||
config SOC_CPU_HAS_DSP
|
||||
bool
|
||||
default y
|
||||
|
||||
config SOC_CPU_COPROC_NUM
|
||||
int
|
||||
default 2
|
||||
|
@@ -161,6 +161,7 @@
|
||||
#define SOC_BRANCH_PREDICTOR_SUPPORTED 1
|
||||
#define SOC_CPU_HAS_FPU 1
|
||||
#define SOC_CPU_HAS_FPU_EXT_ILL_BUG 0 // EXT_ILL CSR doesn't support FLW/FSW
|
||||
#define SOC_CPU_HAS_DSP 1
|
||||
#define SOC_CPU_COPROC_NUM 2
|
||||
|
||||
#define SOC_CPU_BREAKPOINTS_NUM 4
|
||||
|
Reference in New Issue
Block a user