mirror of
https://github.com/espressif/esp-idf.git
synced 2025-08-01 03:34:32 +02:00
Merge branch 'feature/riscv_test_branch_cleanup' into 'master'
cleanup: move freertos code out from riscv component plus complete the interrupt-allocator implementation for C3 Closes IDF-2126, IDF-2228, IDF-2301, and IDF-2545 See merge request espressif/esp-idf!11136
This commit is contained in:
@@ -1,9 +1,9 @@
|
||||
// Copyright 2015-2018 Espressif Systems (Shanghai) PTE LTD
|
||||
// Copyright 2015-2020 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
@@ -12,14 +12,14 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "sdkconfig.h"
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
#include "sdkconfig.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include <esp_types.h>
|
||||
#include "esp_types.h"
|
||||
#include "esp_err.h"
|
||||
#include "esp_intr_alloc.h"
|
||||
#include "esp_attr.h"
|
||||
@@ -29,6 +29,7 @@
|
||||
#include "driver/periph_ctrl.h"
|
||||
#include "esp_int_wdt.h"
|
||||
#include "esp_private/system_internal.h"
|
||||
#include "hal/cpu_hal.h"
|
||||
#include "hal/timer_types.h"
|
||||
#include "hal/wdt_hal.h"
|
||||
#include "hal/interrupt_controller_hal.h"
|
||||
@@ -45,7 +46,7 @@ static wdt_hal_context_t iwdt_context;
|
||||
|
||||
#if CONFIG_ESP32_ECO3_CACHE_LOCK_FIX
|
||||
/*
|
||||
* This parameter is indicates the response time of Interrupt watchdog to
|
||||
* This parameter is used to indicate the response time of Interrupt watchdog to
|
||||
* identify the live lock.
|
||||
*/
|
||||
#define IWDT_LIVELOCK_TIMEOUT_MS (20)
|
||||
@@ -58,8 +59,9 @@ extern uint32_t _l4_intr_livelock_counter, _l4_intr_livelock_max;
|
||||
//Not static; the ISR assembly checks this.
|
||||
bool int_wdt_app_cpu_ticked = false;
|
||||
|
||||
static void IRAM_ATTR tick_hook(void) {
|
||||
if (xPortGetCoreID()!=0) {
|
||||
static void IRAM_ATTR tick_hook(void)
|
||||
{
|
||||
if (cpu_hal_get_core_id() != 0) {
|
||||
int_wdt_app_cpu_ticked = true;
|
||||
} else {
|
||||
//Only feed wdt if app cpu also ticked.
|
||||
@@ -70,11 +72,11 @@ static void IRAM_ATTR tick_hook(void) {
|
||||
#if CONFIG_ESP32_ECO3_CACHE_LOCK_FIX
|
||||
_l4_intr_livelock_counter = 0;
|
||||
wdt_hal_config_stage(&iwdt_context, WDT_STAGE0,
|
||||
CONFIG_ESP_INT_WDT_TIMEOUT_MS*1000/IWDT_TICKS_PER_US/(_l4_intr_livelock_max+1), WDT_STAGE_ACTION_INT); //Set timeout before interrupt
|
||||
CONFIG_ESP_INT_WDT_TIMEOUT_MS * 1000 / IWDT_TICKS_PER_US / (_l4_intr_livelock_max + 1), WDT_STAGE_ACTION_INT); //Set timeout before interrupt
|
||||
#else
|
||||
wdt_hal_config_stage(&iwdt_context, WDT_STAGE0, CONFIG_ESP_INT_WDT_TIMEOUT_MS*1000/IWDT_TICKS_PER_US, WDT_STAGE_ACTION_INT); //Set timeout before interrupt
|
||||
wdt_hal_config_stage(&iwdt_context, WDT_STAGE0, CONFIG_ESP_INT_WDT_TIMEOUT_MS * 1000 / IWDT_TICKS_PER_US, WDT_STAGE_ACTION_INT); //Set timeout before interrupt
|
||||
#endif
|
||||
wdt_hal_config_stage(&iwdt_context, WDT_STAGE1, 2*CONFIG_ESP_INT_WDT_TIMEOUT_MS*1000/IWDT_TICKS_PER_US, WDT_STAGE_ACTION_RESET_SYSTEM); //Set timeout before reset
|
||||
wdt_hal_config_stage(&iwdt_context, WDT_STAGE1, 2 * CONFIG_ESP_INT_WDT_TIMEOUT_MS * 1000 / IWDT_TICKS_PER_US, WDT_STAGE_ACTION_RESET_SYSTEM); //Set timeout before reset
|
||||
wdt_hal_feed(&iwdt_context);
|
||||
wdt_hal_write_protect_enable(&iwdt_context);
|
||||
int_wdt_app_cpu_ticked = false;
|
||||
@@ -82,32 +84,31 @@ static void IRAM_ATTR tick_hook(void) {
|
||||
}
|
||||
}
|
||||
#else
|
||||
static void IRAM_ATTR tick_hook(void) {
|
||||
static void IRAM_ATTR tick_hook(void)
|
||||
{
|
||||
#if !CONFIG_FREERTOS_UNICORE
|
||||
if (xPortGetCoreID()!=0) {
|
||||
if (cpu_hal_get_core_id() != 0) {
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
//Todo: Check if there's a way to avoid reconfiguring the stages on each feed.
|
||||
wdt_hal_write_protect_disable(&iwdt_context);
|
||||
//Reconfigure stage timeouts
|
||||
wdt_hal_config_stage(&iwdt_context, WDT_STAGE0, CONFIG_ESP_INT_WDT_TIMEOUT_MS*1000/IWDT_TICKS_PER_US, WDT_STAGE_ACTION_INT); //Set timeout before interrupt
|
||||
wdt_hal_config_stage(&iwdt_context, WDT_STAGE1, 2*CONFIG_ESP_INT_WDT_TIMEOUT_MS*1000/IWDT_TICKS_PER_US, WDT_STAGE_ACTION_RESET_SYSTEM); //Set timeout before reset
|
||||
wdt_hal_config_stage(&iwdt_context, WDT_STAGE0, CONFIG_ESP_INT_WDT_TIMEOUT_MS * 1000 / IWDT_TICKS_PER_US, WDT_STAGE_ACTION_INT); //Set timeout before interrupt
|
||||
wdt_hal_config_stage(&iwdt_context, WDT_STAGE1, 2 * CONFIG_ESP_INT_WDT_TIMEOUT_MS * 1000 / IWDT_TICKS_PER_US, WDT_STAGE_ACTION_RESET_SYSTEM); //Set timeout before reset
|
||||
wdt_hal_feed(&iwdt_context);
|
||||
wdt_hal_write_protect_enable(&iwdt_context);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
void esp_int_wdt_init(void) {
|
||||
void esp_int_wdt_init(void)
|
||||
{
|
||||
periph_module_enable(PERIPH_TIMG1_MODULE);
|
||||
//The timer configs initially are set to 5 seconds, to make sure the CPU can start up. The tick hook sets
|
||||
//it to their actual value.
|
||||
wdt_hal_init(&iwdt_context, IWDT_INSTANCE, IWDT_PRESCALER, true);
|
||||
wdt_hal_write_protect_disable(&iwdt_context);
|
||||
//The timer configs initially are set to 5 seconds, to make sure the CPU can start up. The tick hook sets
|
||||
//it to their actual value.
|
||||
|
||||
//1st stage timeout: interrupt
|
||||
wdt_hal_config_stage(&iwdt_context, WDT_STAGE0, IWDT_INITIAL_TIMEOUT_S * 1000000 / IWDT_TICKS_PER_US, WDT_STAGE_ACTION_INT);
|
||||
//2nd stage timeout: reset system
|
||||
@@ -119,18 +120,15 @@ void esp_int_wdt_init(void) {
|
||||
|
||||
void esp_int_wdt_cpu_init(void)
|
||||
{
|
||||
assert((CONFIG_ESP_INT_WDT_TIMEOUT_MS >= (portTICK_PERIOD_MS<<1)) && "Interrupt watchdog timeout needs to meet twice the RTOS tick period!");
|
||||
esp_register_freertos_tick_hook_for_cpu(tick_hook, xPortGetCoreID());
|
||||
assert((CONFIG_ESP_INT_WDT_TIMEOUT_MS >= (portTICK_PERIOD_MS << 1)) && "Interrupt watchdog timeout needs to meet twice the RTOS tick period!");
|
||||
esp_register_freertos_tick_hook_for_cpu(tick_hook, cpu_hal_get_core_id());
|
||||
ESP_INTR_DISABLE(WDT_INT_NUM);
|
||||
intr_matrix_set(xPortGetCoreID(), ETS_TG1_WDT_LEVEL_INTR_SOURCE, WDT_INT_NUM);
|
||||
intr_matrix_set(cpu_hal_get_core_id(), ETS_TG1_WDT_LEVEL_INTR_SOURCE, WDT_INT_NUM);
|
||||
|
||||
/* Set the type and priority to cache error interrupts, if supported. */
|
||||
#if SOC_INTERRUPT_TYPE_CAN_SET
|
||||
interrupt_controller_hal_set_type(WDT_INT_NUM, INTR_TYPE_LEVEL);
|
||||
#endif
|
||||
|
||||
#if SOC_INTERRUPT_LEVEL_CAN_SET
|
||||
interrupt_controller_hal_set_level(WDT_INT_NUM, SOC_INTERRUPT_LEVEL_MEDIUM);
|
||||
/* Set the type and priority to watch dog interrupts */
|
||||
#if SOC_CPU_HAS_FLEXIBLE_INTC
|
||||
interrupt_controller_hal_set_int_type(WDT_INT_NUM, INTR_TYPE_LEVEL);
|
||||
interrupt_controller_hal_set_int_level(WDT_INT_NUM, SOC_INTERRUPT_LEVEL_MEDIUM);
|
||||
#endif
|
||||
|
||||
#if CONFIG_ESP32_ECO3_CACHE_LOCK_FIX
|
||||
@@ -140,15 +138,15 @@ void esp_int_wdt_cpu_init(void)
|
||||
*/
|
||||
_l4_intr_livelock_counter = 0;
|
||||
if (soc_has_cache_lock_bug()) {
|
||||
assert((portTICK_PERIOD_MS<<1) <= IWDT_LIVELOCK_TIMEOUT_MS);
|
||||
assert(CONFIG_ESP_INT_WDT_TIMEOUT_MS >= (IWDT_LIVELOCK_TIMEOUT_MS*3));
|
||||
_l4_intr_livelock_max = CONFIG_ESP_INT_WDT_TIMEOUT_MS/IWDT_LIVELOCK_TIMEOUT_MS - 1;
|
||||
assert((portTICK_PERIOD_MS << 1) <= IWDT_LIVELOCK_TIMEOUT_MS);
|
||||
assert(CONFIG_ESP_INT_WDT_TIMEOUT_MS >= (IWDT_LIVELOCK_TIMEOUT_MS * 3));
|
||||
_l4_intr_livelock_max = CONFIG_ESP_INT_WDT_TIMEOUT_MS / IWDT_LIVELOCK_TIMEOUT_MS - 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
//We do not register a handler for the interrupt because it is interrupt level 4 which
|
||||
//is not servicable from C. Instead, xtensa_vectors.S has a call to the panic handler for
|
||||
//this interrupt.
|
||||
// We do not register a handler for the watchdog interrupt because:
|
||||
// 1. Interrupt level 4 on Xtensa architecture is not servicable from C
|
||||
// 2. Instead, we set the entry of watchdog interrupt to the panic handler, see riscv/vector.S and xtensa_vectors.S
|
||||
ESP_INTR_ENABLE(WDT_INT_NUM);
|
||||
}
|
||||
|
||||
|
@@ -1,4 +1,4 @@
|
||||
// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
|
||||
// Copyright 2015-2020 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
@@ -12,8 +12,7 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef __ESP_INTR_ALLOC_H__
|
||||
#define __ESP_INTR_ALLOC_H__
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
@@ -37,24 +36,24 @@ extern "C" {
|
||||
*/
|
||||
|
||||
//Keep the LEVELx values as they are here; they match up with (1<<level)
|
||||
#define ESP_INTR_FLAG_LEVEL1 (1<<1) ///< Accept a Level 1 interrupt vector (lowest priority)
|
||||
#define ESP_INTR_FLAG_LEVEL2 (1<<2) ///< Accept a Level 2 interrupt vector
|
||||
#define ESP_INTR_FLAG_LEVEL3 (1<<3) ///< Accept a Level 3 interrupt vector
|
||||
#define ESP_INTR_FLAG_LEVEL4 (1<<4) ///< Accept a Level 4 interrupt vector
|
||||
#define ESP_INTR_FLAG_LEVEL5 (1<<5) ///< Accept a Level 5 interrupt vector
|
||||
#define ESP_INTR_FLAG_LEVEL6 (1<<6) ///< Accept a Level 6 interrupt vector
|
||||
#define ESP_INTR_FLAG_NMI (1<<7) ///< Accept a Level 7 interrupt vector (highest priority)
|
||||
#define ESP_INTR_FLAG_SHARED (1<<8) ///< Interrupt can be shared between ISRs
|
||||
#define ESP_INTR_FLAG_EDGE (1<<9) ///< Edge-triggered interrupt
|
||||
#define ESP_INTR_FLAG_IRAM (1<<10) ///< ISR can be called if cache is disabled
|
||||
#define ESP_INTR_FLAG_INTRDISABLED (1<<11) ///< Return with this interrupt disabled
|
||||
#define ESP_INTR_FLAG_LEVEL1 (1<<1) ///< Accept a Level 1 interrupt vector (lowest priority)
|
||||
#define ESP_INTR_FLAG_LEVEL2 (1<<2) ///< Accept a Level 2 interrupt vector
|
||||
#define ESP_INTR_FLAG_LEVEL3 (1<<3) ///< Accept a Level 3 interrupt vector
|
||||
#define ESP_INTR_FLAG_LEVEL4 (1<<4) ///< Accept a Level 4 interrupt vector
|
||||
#define ESP_INTR_FLAG_LEVEL5 (1<<5) ///< Accept a Level 5 interrupt vector
|
||||
#define ESP_INTR_FLAG_LEVEL6 (1<<6) ///< Accept a Level 6 interrupt vector
|
||||
#define ESP_INTR_FLAG_NMI (1<<7) ///< Accept a Level 7 interrupt vector (highest priority)
|
||||
#define ESP_INTR_FLAG_SHARED (1<<8) ///< Interrupt can be shared between ISRs
|
||||
#define ESP_INTR_FLAG_EDGE (1<<9) ///< Edge-triggered interrupt
|
||||
#define ESP_INTR_FLAG_IRAM (1<<10) ///< ISR can be called if cache is disabled
|
||||
#define ESP_INTR_FLAG_INTRDISABLED (1<<11) ///< Return with this interrupt disabled
|
||||
|
||||
#define ESP_INTR_FLAG_LOWMED (ESP_INTR_FLAG_LEVEL1|ESP_INTR_FLAG_LEVEL2|ESP_INTR_FLAG_LEVEL3) ///< Low and medium prio interrupts. These can be handled in C.
|
||||
#define ESP_INTR_FLAG_HIGH (ESP_INTR_FLAG_LEVEL4|ESP_INTR_FLAG_LEVEL5|ESP_INTR_FLAG_LEVEL6|ESP_INTR_FLAG_NMI) ///< High level interrupts. Need to be handled in assembly.
|
||||
#define ESP_INTR_FLAG_LOWMED (ESP_INTR_FLAG_LEVEL1|ESP_INTR_FLAG_LEVEL2|ESP_INTR_FLAG_LEVEL3) ///< Low and medium prio interrupts. These can be handled in C.
|
||||
#define ESP_INTR_FLAG_HIGH (ESP_INTR_FLAG_LEVEL4|ESP_INTR_FLAG_LEVEL5|ESP_INTR_FLAG_LEVEL6|ESP_INTR_FLAG_NMI) ///< High level interrupts. Need to be handled in assembly.
|
||||
|
||||
#define ESP_INTR_FLAG_LEVELMASK (ESP_INTR_FLAG_LEVEL1|ESP_INTR_FLAG_LEVEL2|ESP_INTR_FLAG_LEVEL3| \
|
||||
ESP_INTR_FLAG_LEVEL4|ESP_INTR_FLAG_LEVEL5|ESP_INTR_FLAG_LEVEL6| \
|
||||
ESP_INTR_FLAG_NMI) ///< Mask for all level flags
|
||||
#define ESP_INTR_FLAG_LEVELMASK (ESP_INTR_FLAG_LEVEL1|ESP_INTR_FLAG_LEVEL2|ESP_INTR_FLAG_LEVEL3| \
|
||||
ESP_INTR_FLAG_LEVEL4|ESP_INTR_FLAG_LEVEL5|ESP_INTR_FLAG_LEVEL6| \
|
||||
ESP_INTR_FLAG_NMI) ///< Mask for all level flags
|
||||
|
||||
|
||||
/** @addtogroup Intr_Alloc_Pseudo_Src
|
||||
@@ -67,18 +66,18 @@ extern "C" {
|
||||
* sources that do not pass through the interrupt mux. To allocate an interrupt for these sources,
|
||||
* pass these pseudo-sources to the functions.
|
||||
*/
|
||||
#define ETS_INTERNAL_TIMER0_INTR_SOURCE -1 ///< Platform timer 0 interrupt source
|
||||
#define ETS_INTERNAL_TIMER1_INTR_SOURCE -2 ///< Platform timer 1 interrupt source
|
||||
#define ETS_INTERNAL_TIMER2_INTR_SOURCE -3 ///< Platform timer 2 interrupt source
|
||||
#define ETS_INTERNAL_SW0_INTR_SOURCE -4 ///< Software int source 1
|
||||
#define ETS_INTERNAL_SW1_INTR_SOURCE -5 ///< Software int source 2
|
||||
#define ETS_INTERNAL_PROFILING_INTR_SOURCE -6 ///< Int source for profiling
|
||||
#define ETS_INTERNAL_TIMER0_INTR_SOURCE -1 ///< Platform timer 0 interrupt source
|
||||
#define ETS_INTERNAL_TIMER1_INTR_SOURCE -2 ///< Platform timer 1 interrupt source
|
||||
#define ETS_INTERNAL_TIMER2_INTR_SOURCE -3 ///< Platform timer 2 interrupt source
|
||||
#define ETS_INTERNAL_SW0_INTR_SOURCE -4 ///< Software int source 1
|
||||
#define ETS_INTERNAL_SW1_INTR_SOURCE -5 ///< Software int source 2
|
||||
#define ETS_INTERNAL_PROFILING_INTR_SOURCE -6 ///< Int source for profiling
|
||||
|
||||
/**@}*/
|
||||
|
||||
/** Provides SystemView with positive IRQ IDs, otherwise scheduler events are not shown properly
|
||||
*/
|
||||
#define ETS_INTERNAL_INTR_SOURCE_OFF (-ETS_INTERNAL_PROFILING_INTR_SOURCE)
|
||||
#define ETS_INTERNAL_INTR_SOURCE_OFF (-ETS_INTERNAL_PROFILING_INTR_SOURCE)
|
||||
|
||||
/** Enable interrupt by interrupt number */
|
||||
#define ESP_INTR_ENABLE(inum) esp_intr_enable_source(inum)
|
||||
@@ -93,7 +92,7 @@ typedef void (*intr_handler_t)(void *arg);
|
||||
typedef struct intr_handle_data_t intr_handle_data_t;
|
||||
|
||||
/** Handle to an interrupt handler */
|
||||
typedef intr_handle_data_t* intr_handle_t ;
|
||||
typedef intr_handle_data_t *intr_handle_t ;
|
||||
|
||||
/**
|
||||
* @brief Mark an interrupt as a shared interrupt
|
||||
@@ -306,11 +305,18 @@ void esp_intr_enable_source(int inum);
|
||||
*/
|
||||
void esp_intr_disable_source(int inum);
|
||||
|
||||
/**
|
||||
* @brief Get the lowest interrupt level from the flags
|
||||
* @param flags The same flags that pass to `esp_intr_alloc_intrstatus` API
|
||||
*/
|
||||
static inline int esp_intr_flags_to_level(int flags)
|
||||
{
|
||||
return __builtin_ffs((flags & ESP_INTR_FLAG_LEVELMASK) >> 1) + 1;
|
||||
}
|
||||
|
||||
/**@}*/
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
@@ -1,9 +1,9 @@
|
||||
// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
|
||||
// Copyright 2015-2020 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
@@ -12,7 +12,6 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "sdkconfig.h"
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
@@ -21,6 +20,7 @@
|
||||
#include <esp_types.h>
|
||||
#include <limits.h>
|
||||
#include <assert.h>
|
||||
#include "sdkconfig.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "esp_err.h"
|
||||
@@ -48,7 +48,8 @@ Define this to debug the choices made when allocating the interrupt. This leads
|
||||
output within a critical region, which can lead to weird effects like e.g. the interrupt watchdog
|
||||
being triggered, that is why it is separate from the normal LOG* scheme.
|
||||
*/
|
||||
//define DEBUG_INT_ALLOC_DECISIONS
|
||||
// #define DEBUG_INT_ALLOC_DECISIONS
|
||||
|
||||
#ifdef DEBUG_INT_ALLOC_DECISIONS
|
||||
# define ALCHLOG(...) ESP_EARLY_LOGD(TAG, __VA_ARGS__)
|
||||
#else
|
||||
@@ -237,6 +238,8 @@ static bool is_vect_desc_usable(vector_desc_t *vd, int flags, int cpu, int force
|
||||
ALCHLOG("....Unusable: special-purpose int");
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifndef SOC_CPU_HAS_FLEXIBLE_INTC
|
||||
//Check if the interrupt level is acceptable
|
||||
if (!(flags&(1<<interrupt_controller_hal_get_level(x)))) {
|
||||
ALCHLOG("....Unusable: incompatible level");
|
||||
@@ -244,10 +247,12 @@ static bool is_vect_desc_usable(vector_desc_t *vd, int flags, int cpu, int force
|
||||
}
|
||||
//check if edge/level type matches what we want
|
||||
if (((flags&ESP_INTR_FLAG_EDGE) && (interrupt_controller_hal_get_type(x)==INTTP_LEVEL)) ||
|
||||
(((!(flags&ESP_INTR_FLAG_EDGE)) && (interrupt_controller_hal_get_type(x)==INTTP_EDGE)))) {
|
||||
(((!(flags&ESP_INTR_FLAG_EDGE)) && (interrupt_controller_hal_get_type(x)==INTTP_EDGE)))) {
|
||||
ALCHLOG("....Unusable: incompatible trigger type");
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
//check if interrupt is reserved at runtime
|
||||
if (vd->flags&VECDESC_FL_RESERVED) {
|
||||
ALCHLOG("....Unusable: reserved at runtime.");
|
||||
@@ -551,14 +556,11 @@ esp_err_t esp_intr_alloc_intrstatus(int source, int flags, uint32_t intrstatusre
|
||||
interrupt_controller_hal_set_int_handler(intr, handler, arg);
|
||||
#endif
|
||||
}
|
||||
#ifdef __XTENSA__ // TODO ESP32-C3 IDF-2126
|
||||
if (flags&ESP_INTR_FLAG_EDGE) xthal_set_intclear(1 << intr);
|
||||
#else
|
||||
|
||||
if (flags & ESP_INTR_FLAG_EDGE) {
|
||||
ESP_INTR_DISABLE(intr);
|
||||
esprv_intc_int_set_priority(intr, 0);
|
||||
interrupt_controller_hal_edge_int_acknowledge(intr);
|
||||
}
|
||||
#endif
|
||||
|
||||
vd->source=source;
|
||||
}
|
||||
if (flags&ESP_INTR_FLAG_IRAM) {
|
||||
@@ -585,11 +587,16 @@ esp_err_t esp_intr_alloc_intrstatus(int source, int flags, uint32_t intrstatusre
|
||||
esp_intr_disable(ret);
|
||||
}
|
||||
|
||||
#if CONFIG_IDF_TARGET_ESP32C3
|
||||
// TODO ESP32-C3 IDF-2126, these need to be set or the new interrupt won't fire, but are currently hard-coded
|
||||
// for priority and level...
|
||||
esprv_intc_int_set_priority(intr, 1);
|
||||
esprv_intc_int_set_type(BIT(intr), INTR_TYPE_LEVEL);
|
||||
#ifdef SOC_CPU_HAS_FLEXIBLE_INTC
|
||||
//Extract the level from the interrupt passed flags
|
||||
int level = esp_intr_flags_to_level(flags);
|
||||
interrupt_controller_hal_set_int_level(intr, level);
|
||||
|
||||
if (flags & ESP_INTR_FLAG_EDGE) {
|
||||
interrupt_controller_hal_set_int_type(intr, INTTP_EDGE);
|
||||
} else {
|
||||
interrupt_controller_hal_set_int_type(intr, INTTP_LEVEL);
|
||||
}
|
||||
#endif
|
||||
|
||||
portEXIT_CRITICAL(&spinlock);
|
||||
|
@@ -77,19 +77,23 @@
|
||||
#include <string.h>
|
||||
#include "FreeRTOS.h"
|
||||
#include "task.h"
|
||||
#include "sdkconfig.h"
|
||||
#include "portmacro.h"
|
||||
#include "riscv/interrupt.h"
|
||||
#include "riscv/rvruntime-frames.h"
|
||||
|
||||
#include "sdkconfig.h"
|
||||
|
||||
#include "soc/periph_defs.h"
|
||||
#include "soc/system_reg.h"
|
||||
#include "soc/interrupt_reg.h"
|
||||
#include "hal/systimer_hal.h"
|
||||
#include "hal/systimer_ll.h"
|
||||
|
||||
#include "riscv/rvruntime-frames.h"
|
||||
#include "riscv/riscv_interrupts.h"
|
||||
#include "riscv/interrupt.h"
|
||||
|
||||
#include "esp_system.h"
|
||||
#include "esp_intr_alloc.h"
|
||||
#include "esp_private/crosscore_int.h"
|
||||
#include "esp_attr.h"
|
||||
#include "esp_log.h"
|
||||
|
||||
/**
|
||||
@@ -102,15 +106,14 @@ static UBaseType_t uxCriticalNesting = 0;
|
||||
static UBaseType_t uxSavedInterruptState = 0;
|
||||
BaseType_t uxSchedulerRunning = 0;
|
||||
UBaseType_t uxInterruptNesting = 0;
|
||||
BaseType_t xPortSwitchFlag = 0;
|
||||
__attribute__((aligned(16))) static StackType_t xIsrStack[configISR_STACK_SIZE];
|
||||
StackType_t *xIsrStackTop = &xIsrStack[0] + (configISR_STACK_SIZE & (~((portPOINTER_SIZE_TYPE)portBYTE_ALIGNMENT_MASK)));
|
||||
|
||||
static const char *TAG = "cpu_start"; // [refactor-todo]: might be appropriate to change in the future, but
|
||||
|
||||
static void vPortSysTickHandler(void);
|
||||
static void vPortSysTickHandler(void *arg);
|
||||
static void vPortSetupTimer(void);
|
||||
static void vPortSetupSoftwareInterrupt(void);
|
||||
static void vPortSoftwareInterrupt(void);
|
||||
static void prvTaskExitError(void);
|
||||
|
||||
extern void esprv_intc_int_set_threshold(int); // FIXME, this function is in ROM only
|
||||
@@ -121,7 +124,6 @@ void vPortEnterCritical(void)
|
||||
uxCriticalNesting++;
|
||||
|
||||
if (uxCriticalNesting == 1) {
|
||||
//portDISABLE_INTERRUPTS();
|
||||
uxSavedInterruptState = state;
|
||||
}
|
||||
}
|
||||
@@ -132,7 +134,6 @@ void vPortExitCritical(void)
|
||||
uxCriticalNesting--;
|
||||
if (uxCriticalNesting == 0) {
|
||||
portEXIT_CRITICAL_NESTED(uxSavedInterruptState);
|
||||
//portENABLE_INTERRUPTS();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -143,16 +144,9 @@ void vPortExitCritical(void)
|
||||
*/
|
||||
void vPortSetupTimer(void)
|
||||
{
|
||||
/* register the interrupt handler */
|
||||
intr_handler_set(ETS_SYSTICK_INUM, (intr_handler_t)&vPortSysTickHandler, NULL);
|
||||
|
||||
/* pass the timer interrupt through the interrupt matrix */
|
||||
intr_matrix_route(ETS_SYSTIMER_TARGET0_EDGE_INTR_SOURCE, ETS_SYSTICK_INUM);
|
||||
|
||||
/* enable the interrupt in the INTC */
|
||||
esprv_intc_int_enable(BIT(ETS_SYSTICK_INUM));
|
||||
esprv_intc_int_set_type(BIT(ETS_SYSTICK_INUM), INTR_TYPE_LEVEL);
|
||||
esprv_intc_int_set_priority(ETS_SYSTICK_INUM, 1);
|
||||
/* set system timer interrupt vector */
|
||||
esp_err_t err = esp_intr_alloc(ETS_SYSTIMER_TARGET0_EDGE_INTR_SOURCE, ESP_INTR_FLAG_IRAM, vPortSysTickHandler, NULL, NULL);
|
||||
assert(err == ESP_OK);
|
||||
|
||||
/* configure the timer */
|
||||
systimer_hal_init();
|
||||
@@ -163,24 +157,6 @@ void vPortSetupTimer(void)
|
||||
systimer_hal_connect_alarm_counter(SYSTIMER_ALARM_0, SYSTIMER_COUNTER_1);
|
||||
}
|
||||
|
||||
/* setup software interrupt */
|
||||
void vPortSetupSoftwareInterrupt(void)
|
||||
{
|
||||
/* register the interrupt handler, see interrupt.h */
|
||||
intr_handler_set(ETS_CPU_INTR0_INUM, (intr_handler_t)&vPortSoftwareInterrupt, NULL);
|
||||
|
||||
/* pass the "FROM_CPU_0", a.k.a. cross-core interrupt, through the interrupt matrix */
|
||||
intr_matrix_route(ETS_FROM_CPU_INTR0_SOURCE, ETS_CPU_INTR0_INUM);
|
||||
|
||||
/* enable the interrupt in the INTC */
|
||||
esprv_intc_int_enable(BIT(ETS_CPU_INTR0_INUM));
|
||||
esprv_intc_int_set_type(BIT(ETS_CPU_INTR0_INUM), INTR_TYPE_LEVEL);
|
||||
esprv_intc_int_set_priority(ETS_CPU_INTR0_INUM, 1);
|
||||
|
||||
// TODO ESP32-C3 IDF-2126, maybe can use interrupt allocation API for all of the above? unsure...
|
||||
esp_intr_reserve(ETS_CPU_INTR0_INUM, xPortGetCoreID());
|
||||
}
|
||||
|
||||
void prvTaskExitError(void)
|
||||
{
|
||||
/* A function that implements a task must not exit or attempt to return to
|
||||
@@ -191,8 +167,7 @@ void prvTaskExitError(void)
|
||||
defined, then stop here so application writers can catch the error. */
|
||||
configASSERT(uxCriticalNesting == ~0UL);
|
||||
portDISABLE_INTERRUPTS();
|
||||
for (;;)
|
||||
;
|
||||
abort();
|
||||
}
|
||||
|
||||
/* Clear current interrupt mask and set given mask */
|
||||
@@ -212,9 +187,6 @@ int vPortSetInterruptMask(void)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* See header file for description.
|
||||
*/
|
||||
StackType_t *pxPortInitialiseStack(StackType_t *pxTopOfStack, TaskFunction_t pxCode, void *pvParameters)
|
||||
{
|
||||
extern uint32_t __global_pointer$;
|
||||
@@ -231,11 +203,15 @@ StackType_t *pxPortInitialiseStack(StackType_t *pxTopOfStack, TaskFunction_t pxC
|
||||
frame->a1 = 0x11111111;
|
||||
frame->a2 = 0x22222222;
|
||||
frame->a3 = 0x33333333;
|
||||
|
||||
//TODO: IDF-2393
|
||||
return (StackType_t *)frame;
|
||||
}
|
||||
|
||||
void vPortSysTickHandler(void)
|
||||
IRAM_ATTR void vPortSysTickHandler(void *arg)
|
||||
{
|
||||
(void)arg;
|
||||
|
||||
systimer_ll_clear_alarm_int(SYSTIMER_ALARM_0);
|
||||
|
||||
if (!uxSchedulerRunning) {
|
||||
@@ -243,19 +219,23 @@ void vPortSysTickHandler(void)
|
||||
}
|
||||
|
||||
if (xTaskIncrementTick() != pdFALSE) {
|
||||
vTaskSwitchContext();
|
||||
vPortYieldFromISR();
|
||||
}
|
||||
}
|
||||
|
||||
BaseType_t xPortStartScheduler(void)
|
||||
{
|
||||
vPortSetupTimer();
|
||||
vPortSetupSoftwareInterrupt();
|
||||
uxInterruptNesting = 0;
|
||||
uxCriticalNesting = 0;
|
||||
uxSchedulerRunning = 0; /* this means first yield */
|
||||
uxSchedulerRunning = 0;
|
||||
|
||||
vPortSetupTimer();
|
||||
|
||||
esprv_intc_int_set_threshold(1); /* set global INTC masking level */
|
||||
riscv_global_interrupts_enable();
|
||||
|
||||
vPortYield();
|
||||
|
||||
/*Should not get here*/
|
||||
return pdFALSE;
|
||||
}
|
||||
@@ -263,21 +243,18 @@ BaseType_t xPortStartScheduler(void)
|
||||
void vPortEndScheduler(void)
|
||||
{
|
||||
/* very unlikely this function will be called, so just trap here */
|
||||
while (1)
|
||||
;
|
||||
}
|
||||
|
||||
void vPortSoftwareInterrupt(void)
|
||||
{
|
||||
uxSchedulerRunning = 1;
|
||||
vTaskSwitchContext();
|
||||
REG_WRITE(SYSTEM_CPU_INTR_FROM_CPU_0_REG, 0);
|
||||
abort();
|
||||
}
|
||||
|
||||
void vPortYieldOtherCore(BaseType_t coreid)
|
||||
{
|
||||
(void)coreid;
|
||||
vPortYield();
|
||||
esp_crosscore_int_send_yield(coreid);
|
||||
}
|
||||
|
||||
void vPortYieldFromISR( void )
|
||||
{
|
||||
uxSchedulerRunning = 1;
|
||||
xPortSwitchFlag = 1;
|
||||
}
|
||||
|
||||
void vPortYield(void)
|
||||
@@ -285,8 +262,8 @@ void vPortYield(void)
|
||||
if (uxInterruptNesting) {
|
||||
vPortYieldFromISR();
|
||||
} else {
|
||||
REG_WRITE(SYSTEM_CPU_INTR_FROM_CPU_0_REG, 1);
|
||||
|
||||
esp_crosscore_int_send_yield(0);
|
||||
/* There are 3-4 instructions of latency between triggering the software
|
||||
interrupt and the CPU interrupt happening. Make sure it happened before
|
||||
we return, otherwise vTaskDelay() may return and execute 1-2
|
||||
@@ -297,13 +274,9 @@ void vPortYield(void)
|
||||
for an instant yield, and if that happens then the WFI would be
|
||||
waiting for the next interrupt to occur...)
|
||||
*/
|
||||
while(uxSchedulerRunning && uxCriticalNesting == 0 && REG_READ(SYSTEM_CPU_INTR_FROM_CPU_0_REG) != 0) { }
|
||||
while (uxSchedulerRunning && uxCriticalNesting == 0 && REG_READ(SYSTEM_CPU_INTR_FROM_CPU_0_REG) != 0) {}
|
||||
}
|
||||
}
|
||||
|
||||
void vPortYieldFromISR(void)
|
||||
{
|
||||
vTaskSwitchContext();
|
||||
}
|
||||
|
||||
void vPortSetStackWatchpoint(void *pxStackStart)
|
||||
@@ -319,30 +292,30 @@ BaseType_t xPortInIsrContext(void)
|
||||
BaseType_t IRAM_ATTR xPortInterruptedFromISRContext(void)
|
||||
{
|
||||
/* For single core, this can be the same as xPortInIsrContext() because reading it is atomic */
|
||||
return uxInterruptNesting;
|
||||
return uxInterruptNesting;
|
||||
}
|
||||
|
||||
|
||||
void vPortCPUInitializeMutex(portMUX_TYPE *mux)
|
||||
{
|
||||
(void)mux;
|
||||
(void)mux; //TODO: IDF-2393
|
||||
}
|
||||
|
||||
void vPortCPUAcquireMutex(portMUX_TYPE *mux)
|
||||
{
|
||||
(void)mux;
|
||||
(void)mux; //TODO: IDF-2393
|
||||
}
|
||||
|
||||
bool vPortCPUAcquireMutexTimeout(portMUX_TYPE *mux, int timeout_cycles)
|
||||
{
|
||||
(void)mux;
|
||||
(void)mux; //TODO: IDF-2393
|
||||
(void)timeout_cycles;
|
||||
return true;
|
||||
}
|
||||
|
||||
void vPortCPUReleaseMutex(portMUX_TYPE *mux)
|
||||
{
|
||||
(void)mux;
|
||||
(void)mux; //TODO: IDF-2393
|
||||
}
|
||||
|
||||
void __attribute__((weak)) vApplicationStackOverflowHook(TaskHandle_t xTask, char *pcTaskName)
|
||||
|
@@ -37,14 +37,23 @@ rtos_int_enter:
|
||||
|
||||
/* scheduler not enabled, jump directly to ISR handler */
|
||||
lw t0, uxSchedulerRunning
|
||||
beq t0,zero, not_rtos_enter
|
||||
beq t0,zero, rtos_enter_end
|
||||
|
||||
/* Sabe current TCB and load the ISR stack */
|
||||
/* increments the ISR nesting count */
|
||||
la t3, uxInterruptNesting
|
||||
lw t4, 0x0(t3)
|
||||
addi t5,t4,1
|
||||
sw t5, 0x0(t3)
|
||||
|
||||
/* If reached here from another low-prio ISR, skip stack pushing to TCB */
|
||||
bne t4,zero, rtos_enter_end
|
||||
|
||||
/* Save current TCB and load the ISR stack */
|
||||
lw t0, pxCurrentTCB
|
||||
sw t2, 0x0(t0)
|
||||
lw sp, xIsrStackTop
|
||||
|
||||
not_rtos_enter:
|
||||
rtos_enter_end:
|
||||
mv ra, t1
|
||||
ret
|
||||
|
||||
@@ -56,10 +65,23 @@ not_rtos_enter:
|
||||
.global rtos_int_exit
|
||||
.type rtos_int_exit, @function
|
||||
rtos_int_exit:
|
||||
|
||||
/* may skip RTOS aware interrupt since scheduler was not started */
|
||||
lw t0, uxSchedulerRunning
|
||||
beq t0,zero, not_rtos_exit
|
||||
beq t0,zero, rtos_exit_end
|
||||
|
||||
/* update nesting interrupts counter */
|
||||
la t2, uxInterruptNesting
|
||||
lw t3, 0x0(t2)
|
||||
|
||||
/* Already zero, protect against underflow */
|
||||
beq t3, zero, isr_skip_decrement
|
||||
addi t3,t3, -1
|
||||
sw t3, 0x0(t2)
|
||||
|
||||
isr_skip_decrement:
|
||||
|
||||
/* may still have interrupts pending, skip section below and exit */
|
||||
bne t3,zero,rtos_exit_end
|
||||
|
||||
/* Schedule the next task if a yield is pending */
|
||||
la t0, xPortSwitchFlag
|
||||
@@ -83,5 +105,5 @@ no_switch:
|
||||
lw a0, pxCurrentTCB
|
||||
lw a0, 0x0(a0)
|
||||
|
||||
not_rtos_exit:
|
||||
rtos_exit_end:
|
||||
ret
|
||||
|
@@ -28,8 +28,7 @@ if(NOT BOOTLOADER_BUILD)
|
||||
"soc_hal.c"
|
||||
"interrupt_controller_hal.c"
|
||||
"sha_hal.c"
|
||||
"aes_hal.c"
|
||||
"${target}/interrupt_descriptor_table.c")
|
||||
"aes_hal.c")
|
||||
|
||||
if(${target} STREQUAL "esp32")
|
||||
list(APPEND srcs
|
||||
@@ -43,6 +42,7 @@ if(NOT BOOTLOADER_BUILD)
|
||||
"twai_hal_iram.c"
|
||||
"esp32/adc_hal.c"
|
||||
"esp32/brownout_hal.c"
|
||||
"esp32/interrupt_descriptor_table.c"
|
||||
"esp32/touch_sensor_hal.c")
|
||||
if(NOT BOOTLOADER_BUILD AND CONFIG_ETH_USE_ESP32_EMAC)
|
||||
list(APPEND srcs "esp32/emac_hal.c")
|
||||
@@ -65,6 +65,7 @@ if(NOT BOOTLOADER_BUILD)
|
||||
"esp32s2/systimer_hal.c"
|
||||
"esp32s2/touch_sensor_hal.c"
|
||||
"esp32s2/dac_hal.c"
|
||||
"esp32s2/interrupt_descriptor_table.c"
|
||||
"esp32s2/usb_hal.c")
|
||||
endif()
|
||||
|
||||
@@ -79,6 +80,7 @@ if(NOT BOOTLOADER_BUILD)
|
||||
"twai_hal.c"
|
||||
"twai_hal_iram.c"
|
||||
"esp32s3/brownout_hal.c"
|
||||
"esp32s3/interrupt_descriptor_table.c"
|
||||
"esp32s3/systimer_hal.c"
|
||||
"esp32s3/touch_sensor_hal.c")
|
||||
endif()
|
||||
|
@@ -62,7 +62,7 @@ static inline bool intr_cntrl_ll_has_handler(uint8_t intr, uint8_t cpu)
|
||||
* @param handler handler invoked when an interrupt occurs
|
||||
* @param arg optional argument to pass to the handler
|
||||
*/
|
||||
static inline void intr_cntrl_ll_set_int_handler(uint8_t intr, interrupt_handler_t handler, void * arg)
|
||||
static inline void intr_cntrl_ll_set_int_handler(uint8_t intr, interrupt_handler_t handler, void *arg)
|
||||
{
|
||||
xt_set_interrupt_handler(intr, (xt_handler)handler, arg);
|
||||
}
|
||||
@@ -74,7 +74,7 @@ static inline void intr_cntrl_ll_set_int_handler(uint8_t intr, interrupt_handler
|
||||
*
|
||||
* @return argument used by handler of passed interrupt number
|
||||
*/
|
||||
static inline void * intr_cntrl_ll_get_int_handler_arg(uint8_t intr)
|
||||
static inline void *intr_cntrl_ll_get_int_handler_arg(uint8_t intr)
|
||||
{
|
||||
return xt_get_interrupt_handler_arg(intr);
|
||||
}
|
||||
@@ -100,6 +100,16 @@ static inline void intr_cntrl_ll_enable_int_mask(uint32_t newmask)
|
||||
xt_int_enable_mask(newmask);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Acknowledge an edge-trigger interrupt by clearing its pending flag
|
||||
*
|
||||
* @param intr interrupt number ranged from 0 to 31
|
||||
*/
|
||||
static inline void intr_cntrl_ll_edge_int_acknowledge(int intr)
|
||||
{
|
||||
xthal_set_intclear(1 << intr);
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
@@ -30,7 +30,7 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
static inline int cpu_ll_get_core_id(void)
|
||||
static inline int IRAM_ATTR cpu_ll_get_core_id(void)
|
||||
{
|
||||
#if SOC_CPU_CORES_NUM == 1
|
||||
return 0; // No need to check core ID on single core hardware
|
||||
|
@@ -68,7 +68,7 @@ static inline bool intr_cntrl_ll_has_handler(uint8_t intr, uint8_t cpu)
|
||||
* @param handler handler invoked when an interrupt occurs
|
||||
* @param arg optional argument to pass to the handler
|
||||
*/
|
||||
static inline void intr_cntrl_ll_set_int_handler(uint8_t intr, interrupt_handler_t handler, void * arg)
|
||||
static inline void intr_cntrl_ll_set_int_handler(uint8_t intr, interrupt_handler_t handler, void *arg)
|
||||
{
|
||||
intr_handler_set(intr, (void *)handler, arg);
|
||||
}
|
||||
@@ -80,7 +80,7 @@ static inline void intr_cntrl_ll_set_int_handler(uint8_t intr, interrupt_handler
|
||||
*
|
||||
* @return argument used by handler of passed interrupt number
|
||||
*/
|
||||
static inline void * intr_cntrl_ll_get_int_handler_arg(uint8_t intr)
|
||||
static inline void *intr_cntrl_ll_get_int_handler_arg(uint8_t intr)
|
||||
{
|
||||
return intr_handler_get_arg(intr);
|
||||
}
|
||||
@@ -116,27 +116,36 @@ static inline void intr_cntrl_ll_enable_int_mask(uint32_t newmask)
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set the interrupt type given an interrupt number.
|
||||
* @brief Acknowledge an edge-trigger interrupt by clearing its pending flag
|
||||
*
|
||||
* @param interrupt_number number of the interrupt
|
||||
* @param type new type for this interrupt
|
||||
* @param intr interrupt number ranged from 0 to 31
|
||||
*/
|
||||
static inline void intr_cntrl_ll_set_type(int interrupt_number, int_type_t type)
|
||||
static inline void intr_cntrl_ll_edge_int_acknowledge(int intr)
|
||||
{
|
||||
esprv_intc_int_set_type(BIT(interrupt_number), type);
|
||||
REG_SET_BIT(INTERRUPT_CORE0_CPU_INT_CLEAR_REG, intr);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set the interrupt level (priority) given an interrupt number.
|
||||
* @brief Sets the interrupt level int the interrupt controller.
|
||||
*
|
||||
* @param interrupt_number number of the interrupt
|
||||
* @param level new level for this interrupt
|
||||
* @param interrupt_number Interrupt number 0 to 31
|
||||
* @param level priority between 1 (lowest) to 7 (highest)
|
||||
*/
|
||||
static inline void intr_cntrl_ll_set_level(int interrupt_number, int level)
|
||||
static inline void intr_cntrl_ll_set_int_level(int intr, int level)
|
||||
{
|
||||
esprv_intc_int_set_priority(interrupt_number, level);
|
||||
esprv_intc_int_set_priority(intr, level);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set the type of an interrupt in the controller.
|
||||
*
|
||||
* @param interrupt_number Interrupt number 0 to 31
|
||||
* @param type interrupt type as edge or level triggered
|
||||
*/
|
||||
static inline void intr_cntrl_ll_set_int_type(int intr, int_type_t type)
|
||||
{
|
||||
esprv_intc_int_set_type(BIT(intr), type);
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
@@ -1,61 +0,0 @@
|
||||
// Copyright 2020 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
#include "sdkconfig.h"
|
||||
#include "hal/interrupt_controller_hal.h"
|
||||
#include "soc/soc_caps.h"
|
||||
#include "soc/soc.h"
|
||||
|
||||
// TODO ESP32-C3 IDF-2126 check this table is correct, some interrupts may be unnecessarily reserved or not reserved
|
||||
// or marked as the wrong type
|
||||
|
||||
//This is basically a software-readable version of the interrupt usage table in include/soc/soc.h
|
||||
const int_desc_t interrupt_descriptor_table[32] = {
|
||||
{ 1, INTTP_LEVEL, {INTDESC_RESVD } }, //0
|
||||
{ 1, INTTP_LEVEL, {INTDESC_SPECIAL } }, //1
|
||||
{ 1, INTTP_LEVEL, {INTDESC_NORMAL } }, //2
|
||||
{ 1, INTTP_LEVEL, {INTDESC_NORMAL } }, //3
|
||||
{ 1, INTTP_LEVEL, {INTDESC_NORMAL } }, //4
|
||||
{ 1, INTTP_LEVEL, {INTDESC_SPECIAL } }, //5
|
||||
{ 1, INTTP_NA, {INTDESC_NORMAL } }, //6
|
||||
{ 1, INTTP_NA, {INTDESC_NORMAL } }, //7
|
||||
{ 1, INTTP_LEVEL, {INTDESC_SPECIAL } }, //8
|
||||
{ 1, INTTP_LEVEL, {INTDESC_SPECIAL } }, //9
|
||||
{ 1, INTTP_EDGE, {INTDESC_NORMAL } }, //10
|
||||
{ 3, INTTP_NA, {INTDESC_NORMAL } }, //11
|
||||
{ 1, INTTP_LEVEL, {INTDESC_SPECIAL } }, //12
|
||||
{ 1, INTTP_LEVEL, {INTDESC_NORMAL } }, //13
|
||||
{ 7, INTTP_LEVEL, {INTDESC_NORMAL } }, //14
|
||||
{ 3, INTTP_NA, {INTDESC_NORMAL } }, //15
|
||||
{ 5, INTTP_NA, {INTDESC_NORMAL } }, //16
|
||||
{ 1, INTTP_LEVEL, {INTDESC_NORMAL } }, //17
|
||||
{ 1, INTTP_LEVEL, {INTDESC_NORMAL } }, //18
|
||||
{ 2, INTTP_LEVEL, {INTDESC_NORMAL } }, //19
|
||||
{ 2, INTTP_LEVEL, {INTDESC_NORMAL } }, //20
|
||||
{ 2, INTTP_LEVEL, {INTDESC_NORMAL } }, //21
|
||||
{ 3, INTTP_EDGE, {INTDESC_NORMAL } }, //22
|
||||
{ 3, INTTP_LEVEL, {INTDESC_NORMAL } }, //23
|
||||
{ 4, INTTP_LEVEL, {INTDESC_RESVD } }, //24
|
||||
{ 4, INTTP_LEVEL, {INTDESC_RESVD } }, //25
|
||||
{ 5, INTTP_LEVEL, {INTDESC_NORMAL } }, //26
|
||||
{ 3, INTTP_LEVEL, {INTDESC_NORMAL } }, //27
|
||||
{ 4, INTTP_EDGE, {INTDESC_NORMAL } }, //28
|
||||
{ 3, INTTP_NA, {INTDESC_NORMAL } }, //29
|
||||
{ 4, INTTP_EDGE, {INTDESC_NORMAL } }, //30
|
||||
{ 5, INTTP_LEVEL, {INTDESC_NORMAL } }, //31
|
||||
};
|
||||
|
||||
const int_desc_t *interrupt_controller_hal_desc_table(void)
|
||||
{
|
||||
return interrupt_descriptor_table;
|
||||
}
|
@@ -62,7 +62,7 @@ static inline bool intr_cntrl_ll_has_handler(uint8_t intr, uint8_t cpu)
|
||||
* @param handler handler invoked when an interrupt occurs
|
||||
* @param arg optional argument to pass to the handler
|
||||
*/
|
||||
static inline void intr_cntrl_ll_set_int_handler(uint8_t intr, interrupt_handler_t handler, void * arg)
|
||||
static inline void intr_cntrl_ll_set_int_handler(uint8_t intr, interrupt_handler_t handler, void *arg)
|
||||
{
|
||||
xt_set_interrupt_handler(intr, (xt_handler)handler, arg);
|
||||
}
|
||||
@@ -74,7 +74,7 @@ static inline void intr_cntrl_ll_set_int_handler(uint8_t intr, interrupt_handler
|
||||
*
|
||||
* @return argument used by handler of passed interrupt number
|
||||
*/
|
||||
static inline void * intr_cntrl_ll_get_int_handler_arg(uint8_t intr)
|
||||
static inline void *intr_cntrl_ll_get_int_handler_arg(uint8_t intr)
|
||||
{
|
||||
return xt_get_interrupt_handler_arg(intr);
|
||||
}
|
||||
@@ -100,6 +100,15 @@ static inline void intr_cntrl_ll_enable_int_mask(uint32_t newmask)
|
||||
xt_int_enable_mask(newmask);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Acknowledge an edge-trigger interrupt by clearing its pending flag
|
||||
*
|
||||
* @param intr interrupt number ranged from 0 to 31
|
||||
*/
|
||||
static inline void intr_cntrl_ll_edge_int_acknowledge (int intr)
|
||||
{
|
||||
xthal_set_intclear(1 << intr);
|
||||
}
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
@@ -21,13 +21,14 @@
|
||||
#include "xtensa/config/specreg.h"
|
||||
#include "xtensa/config/extreg.h"
|
||||
#include "esp_bit_defs.h"
|
||||
#include "esp_attr.h"
|
||||
#include "xtensa/config/core.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
static inline int cpu_ll_get_core_id(void)
|
||||
static inline int IRAM_ATTR cpu_ll_get_core_id(void)
|
||||
{
|
||||
uint32_t id;
|
||||
asm volatile (
|
||||
|
@@ -62,7 +62,7 @@ static inline bool intr_cntrl_ll_has_handler(uint8_t intr, uint8_t cpu)
|
||||
* @param handler handler invoked when an interrupt occurs
|
||||
* @param arg optional argument to pass to the handler
|
||||
*/
|
||||
static inline void intr_cntrl_ll_set_int_handler(uint8_t intr, interrupt_handler_t handler, void * arg)
|
||||
static inline void intr_cntrl_ll_set_int_handler(uint8_t intr, interrupt_handler_t handler, void *arg)
|
||||
{
|
||||
xt_set_interrupt_handler(intr, (xt_handler)handler, arg);
|
||||
}
|
||||
@@ -74,7 +74,7 @@ static inline void intr_cntrl_ll_set_int_handler(uint8_t intr, interrupt_handler
|
||||
*
|
||||
* @return argument used by handler of passed interrupt number
|
||||
*/
|
||||
static inline void * intr_cntrl_ll_get_int_handler_arg(uint8_t intr)
|
||||
static inline void *intr_cntrl_ll_get_int_handler_arg(uint8_t intr)
|
||||
{
|
||||
return xt_get_interrupt_handler_arg(intr);
|
||||
}
|
||||
@@ -100,6 +100,15 @@ static inline void intr_cntrl_ll_enable_int_mask(uint32_t newmask)
|
||||
xt_int_enable_mask(newmask);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Acknowledge an edge-trigger interrupt by clearing its pending flag
|
||||
*
|
||||
* @param intr interrupt number ranged from 0 to 31
|
||||
*/
|
||||
static inline void intr_cntrl_ll_edge_int_acknowledge (int intr)
|
||||
{
|
||||
xthal_set_intclear(1 << intr);
|
||||
}
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
@@ -23,12 +23,14 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#ifndef SOC_CPU_HAS_FLEXIBLE_INTC
|
||||
/**
|
||||
* @brief Gets target platform interrupt descriptor table
|
||||
*
|
||||
* @return Address of interrupt descriptor table
|
||||
*/
|
||||
__attribute__((pure)) const int_desc_t *interrupt_controller_hal_desc_table(void);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Gets the interrupt type given an interrupt number.
|
||||
@@ -55,24 +57,6 @@ __attribute__((pure)) int interrupt_controller_hal_desc_level(int interrupt_num
|
||||
*/
|
||||
__attribute__((pure)) int_desc_flag_t interrupt_controller_hal_desc_flags(int interrupt_number, int cpu_number);
|
||||
|
||||
#if SOC_INTERRUPT_LEVEL_CAN_SET
|
||||
/**
|
||||
* @brief Set the interrupt level given an interrupt number.
|
||||
*
|
||||
* @param interrupt_number number of the interrupt
|
||||
* @param level new level for this interrupt
|
||||
*/
|
||||
void interrupt_controller_hal_set_level(int interrupt_number, int level);
|
||||
|
||||
/**
|
||||
* @brief Set the interrupt type given an interrupt number.
|
||||
*
|
||||
* @param interrupt_number number of the interrupt
|
||||
* @param type new type for this interrupt
|
||||
*/
|
||||
void interrupt_controller_hal_set_type(int interrupt_number, int_type_t type);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Gets the interrupt type given an interrupt number.
|
||||
*
|
||||
@@ -95,6 +79,30 @@ static inline int interrupt_controller_hal_get_level(int interrupt_number)
|
||||
return interrupt_controller_hal_desc_level(interrupt_number);
|
||||
}
|
||||
|
||||
#ifdef SOC_CPU_HAS_FLEXIBLE_INTC
|
||||
/**
|
||||
* @brief Set the type of an interrupt in the controller.
|
||||
*
|
||||
* @param interrupt_number Interrupt number 0 to 31
|
||||
* @param type interrupt type as edge or level triggered
|
||||
*/
|
||||
static inline void interrupt_controller_hal_set_int_type(int intr, int_type_t type)
|
||||
{
|
||||
intr_cntrl_ll_set_int_type(intr, type);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Sets the interrupt level int the interrupt controller.
|
||||
*
|
||||
* @param interrupt_number Interrupt number 0 to 31
|
||||
* @param level priority between 1 (lowest) to 7 (highest)
|
||||
*/
|
||||
static inline void interrupt_controller_hal_set_int_level(int intr, int level)
|
||||
{
|
||||
intr_cntrl_ll_set_int_level(intr, level);
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Gets the cpu flags given the interrupt number and target cpu.
|
||||
*
|
||||
@@ -184,6 +192,16 @@ static inline void interrupt_controller_hal_enable_int_mask(uint32_t newmask)
|
||||
intr_cntrl_ll_enable_int_mask(newmask);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Acknowledge an edge-trigger interrupt by clearing its pending flag
|
||||
*
|
||||
* @param intr interrupt number ranged from 0 to 31
|
||||
*/
|
||||
static inline void interrupt_controller_hal_edge_int_acknowledge(int intr)
|
||||
{
|
||||
intr_cntrl_ll_edge_int_acknowledge(intr);
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
@@ -24,13 +24,13 @@ extern "C" {
|
||||
typedef enum {
|
||||
INTDESC_NORMAL=0,
|
||||
INTDESC_RESVD,
|
||||
INTDESC_SPECIAL
|
||||
INTDESC_SPECIAL,
|
||||
} int_desc_flag_t;
|
||||
|
||||
typedef enum {
|
||||
INTTP_LEVEL=0,
|
||||
INTTP_EDGE,
|
||||
INTTP_NA
|
||||
INTTP_NA,
|
||||
} int_type_t;
|
||||
|
||||
typedef struct {
|
||||
|
@@ -14,36 +14,52 @@
|
||||
|
||||
#include "hal/interrupt_controller_hal.h"
|
||||
|
||||
#if __riscv
|
||||
#include "riscv/instruction_decode.h"
|
||||
|
||||
static bool is_interrupt_number_reserved(int interrupt_number)
|
||||
{
|
||||
extern int _vector_table;
|
||||
extern int _interrupt_handler;
|
||||
const intptr_t pc = (intptr_t)(&_vector_table + interrupt_number);
|
||||
|
||||
/* JAL instructions are relative to the PC there are executed from. */
|
||||
const intptr_t destination = pc + riscv_decode_offset_from_jal_instruction(pc);
|
||||
|
||||
return destination != (intptr_t)&_interrupt_handler;
|
||||
}
|
||||
#endif
|
||||
|
||||
int_type_t interrupt_controller_hal_desc_type(int interrupt_number)
|
||||
{
|
||||
#ifndef SOC_CPU_HAS_FLEXIBLE_INTC
|
||||
const int_desc_t *int_desc = interrupt_controller_hal_desc_table();
|
||||
return(int_desc[interrupt_number].type);
|
||||
return (int_desc[interrupt_number].type);
|
||||
#else
|
||||
return (INTTP_NA);
|
||||
#endif
|
||||
}
|
||||
|
||||
int interrupt_controller_hal_desc_level(int interrupt_number)
|
||||
{
|
||||
#ifndef SOC_CPU_HAS_FLEXIBLE_INTC
|
||||
const int_desc_t *int_desc = interrupt_controller_hal_desc_table();
|
||||
return(int_desc[interrupt_number].level);
|
||||
return (int_desc[interrupt_number].level);
|
||||
#else
|
||||
return 1;
|
||||
#endif
|
||||
}
|
||||
|
||||
int_desc_flag_t interrupt_controller_hal_desc_flags(int interrupt_number, int cpu_number)
|
||||
{
|
||||
#ifndef SOC_CPU_HAS_FLEXIBLE_INTC
|
||||
const int_desc_t *int_desc = interrupt_controller_hal_desc_table();
|
||||
return(int_desc[interrupt_number].cpuflags[cpu_number]);
|
||||
}
|
||||
|
||||
#if SOC_INTERRUPT_LEVEL_CAN_SET
|
||||
|
||||
void interrupt_controller_hal_set_level(int interrupt_number, int level) {
|
||||
intr_cntrl_ll_set_level(interrupt_number, level);
|
||||
}
|
||||
|
||||
return (int_desc[interrupt_number].cpuflags[cpu_number]);
|
||||
#else
|
||||
#if __riscv
|
||||
return is_interrupt_number_reserved(interrupt_number) ? INTDESC_RESVD : INTDESC_NORMAL;
|
||||
#else
|
||||
return INTDESC_NORMAL;
|
||||
#endif
|
||||
|
||||
#if SOC_INTERRUPT_TYPE_CAN_SET
|
||||
|
||||
void interrupt_controller_hal_set_type(int interrupt_number, int_type_t type) {
|
||||
intr_cntrl_ll_set_type(interrupt_number, type);
|
||||
}
|
||||
|
||||
#endif
|
||||
}
|
||||
|
@@ -7,6 +7,9 @@ if(BOOTLOADER_BUILD)
|
||||
else()
|
||||
set(priv_requires soc freertos)
|
||||
set(srcs
|
||||
"expression_with_stack_riscv.c"
|
||||
"expression_with_stack_riscv_asm.S"
|
||||
"instruction_decode.c"
|
||||
"interrupt.c"
|
||||
"stdatomic.c"
|
||||
"vectors.S")
|
||||
|
79
components/riscv/expression_with_stack_riscv.c
Normal file
79
components/riscv/expression_with_stack_riscv.c
Normal file
@@ -0,0 +1,79 @@
|
||||
// Copyright 2015-2019 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include <esp_expression_with_stack.h>
|
||||
#include <riscv/rvruntime-frames.h>
|
||||
#include <string.h>
|
||||
|
||||
static portMUX_TYPE shared_stack_spinlock = portMUX_INITIALIZER_UNLOCKED;
|
||||
static void *current_task_stack = NULL;
|
||||
|
||||
extern void esp_shared_stack_invoke_function(shared_stack_function function, void *stack);
|
||||
|
||||
static StackType_t *esp_switch_stack_setup(StackType_t *stack, size_t stack_size)
|
||||
{
|
||||
#if CONFIG_FREERTOS_WATCHPOINT_END_OF_STACK
|
||||
// TODO ESP32-C3 IDF-2207
|
||||
// esp_clear_watchpoint(1);
|
||||
// uint32_t watchpoint_place = ((uint32_t)stack + 32) & ~0x1f ;
|
||||
#endif
|
||||
//We need also to tweak current task stackpointer to avoid erroneous
|
||||
//stack overflow indication, so fills the stack with freertos known pattern:
|
||||
memset(stack, 0xa5U, stack_size * sizeof(StackType_t));
|
||||
|
||||
StaticTask_t *current = (StaticTask_t *)xTaskGetCurrentTaskHandle();
|
||||
//Then put the fake stack inside of TCB:
|
||||
current_task_stack = current->pxDummy6;
|
||||
current->pxDummy6 = (void *)stack;
|
||||
|
||||
StackType_t *top_of_stack = stack + stack_size;
|
||||
|
||||
//Align stack to a 16byte boundary, as required by CPU specific:
|
||||
top_of_stack = (StackType_t *)(((UBaseType_t)(top_of_stack - 16) & ~0xf));
|
||||
RvExcFrame *adjusted_top_of_stack = (RvExcFrame *) top_of_stack;
|
||||
adjusted_top_of_stack--;
|
||||
|
||||
#if CONFIG_FREERTOS_WATCHPOINT_END_OF_STACK
|
||||
// TODO ESP32-C3 IDF-2207
|
||||
//esp_set_watchpoint(1, (uint8_t *)watchpoint_place, 32, ESP_WATCHPOINT_STORE);
|
||||
#endif
|
||||
|
||||
return ((StackType_t *)adjusted_top_of_stack);
|
||||
}
|
||||
|
||||
|
||||
void esp_execute_shared_stack_function(SemaphoreHandle_t lock, void *stack, size_t stack_size, shared_stack_function function)
|
||||
{
|
||||
assert(lock);
|
||||
assert(stack);
|
||||
assert(stack_size > 0 && stack_size >= CONFIG_ESP_MINIMAL_SHARED_STACK_SIZE);
|
||||
assert(function);
|
||||
|
||||
xSemaphoreTake(lock, portMAX_DELAY);
|
||||
portENTER_CRITICAL(&shared_stack_spinlock);
|
||||
stack = esp_switch_stack_setup(stack, stack_size);
|
||||
portEXIT_CRITICAL(&shared_stack_spinlock);
|
||||
|
||||
esp_shared_stack_invoke_function(function, stack);
|
||||
|
||||
portENTER_CRITICAL(&shared_stack_spinlock);
|
||||
StaticTask_t *current = (StaticTask_t *)xTaskGetCurrentTaskHandle();
|
||||
|
||||
//Restore current task stack:
|
||||
current->pxDummy6 = (StackType_t *)current_task_stack;
|
||||
vPortSetStackWatchpoint(current->pxDummy6);
|
||||
portEXIT_CRITICAL(&shared_stack_spinlock);
|
||||
|
||||
xSemaphoreGive(lock);
|
||||
}
|
43
components/riscv/expression_with_stack_riscv_asm.S
Normal file
43
components/riscv/expression_with_stack_riscv_asm.S
Normal file
@@ -0,0 +1,43 @@
|
||||
// Copyright 2015-2020 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
.section .text
|
||||
|
||||
.global esp_shared_stack_invoke_function
|
||||
.type esp_shared_stack_invoke_function, @function
|
||||
esp_shared_stack_invoke_function:
|
||||
/* save current stack and return address */
|
||||
mv t0, sp
|
||||
mv t1, ra
|
||||
|
||||
/* Set shared stack as new stack pointer */
|
||||
mv sp, a1
|
||||
|
||||
/* store the ra and previous stack pointer in a safe place */
|
||||
addi sp,sp,-4
|
||||
sw t0, 0(sp)
|
||||
sw t1, 4(sp)
|
||||
|
||||
/* call the subroutine */
|
||||
jalr a0, 0
|
||||
|
||||
/* gets the ra and stack pointer saved previously */
|
||||
lw t0, 0(sp)
|
||||
lw t1, 4(sp)
|
||||
addi sp, sp, 4
|
||||
|
||||
/* restore both ra and real stack pointer of current task */
|
||||
mv ra, t1
|
||||
mv sp, t0
|
||||
ret
|
@@ -3,7 +3,7 @@
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
@@ -14,12 +14,20 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define SOC_INTERRUPT_LEVEL_CAN_SET (1)
|
||||
#define SOC_INTERRUPT_TYPE_CAN_SET (1)
|
||||
/**
|
||||
* @brief Decode the offset value from a RISC-V JAL instruction
|
||||
* @note This API will abort if the instruction is not JAL formatted.
|
||||
*
|
||||
* @param inst_addr Address of JAL instruction
|
||||
* @return int offset value
|
||||
*/
|
||||
int riscv_decode_offset_from_jal_instruction(const intptr_t inst_addr);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
38
components/riscv/instruction_decode.c
Normal file
38
components/riscv/instruction_decode.c
Normal file
@@ -0,0 +1,38 @@
|
||||
// Copyright 2020 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include <stdlib.h>
|
||||
#include "riscv/instruction_decode.h"
|
||||
|
||||
typedef union {
|
||||
struct {
|
||||
unsigned int opcode: 7;
|
||||
unsigned int rd: 5;
|
||||
int imm_19_12: 8;
|
||||
int imm_11: 1;
|
||||
int imm_10_1: 10;
|
||||
int imm20: 1;
|
||||
};
|
||||
unsigned int inst;
|
||||
} riscv_jal_intruction_t;
|
||||
|
||||
int riscv_decode_offset_from_jal_instruction(const intptr_t inst_addr)
|
||||
{
|
||||
riscv_jal_intruction_t *jal_inst = (riscv_jal_intruction_t *)inst_addr;
|
||||
// check if it's a valid JAL instruction
|
||||
if (jal_inst->opcode != 0x6f && jal_inst->rd != 0) {
|
||||
abort();
|
||||
}
|
||||
return (jal_inst->imm_10_1 | jal_inst->imm_11 << 10 | jal_inst->imm_19_12 << 11 | jal_inst->imm20 << 19) << 1;
|
||||
}
|
@@ -97,11 +97,8 @@
|
||||
csrw mepc, t0
|
||||
.endm
|
||||
|
||||
.global vPortYieldFromISR
|
||||
.global uxInterruptNesting
|
||||
.global uxSchedulerRunning
|
||||
.global xIsrStackTop
|
||||
.global pxCurrentTCB
|
||||
.global rtos_int_enter
|
||||
.global rtos_int_exit
|
||||
.global _global_interrupt_handler
|
||||
|
||||
.section .exception_vectors.text
|
||||
@@ -219,25 +216,11 @@ _interrupt_handler:
|
||||
save_regs
|
||||
save_mepc
|
||||
|
||||
/* scheduler not enabled, jump directly to ISR handler */
|
||||
lw t0, uxSchedulerRunning
|
||||
beq t0, zero, already_on_handler
|
||||
/* Before doing anythig preserve the stack pointer */
|
||||
/* It will be saved in current TCB, if needed */
|
||||
mv a0, sp
|
||||
call rtos_int_enter
|
||||
|
||||
/* increments the ISR nesting count */
|
||||
la t0, uxInterruptNesting
|
||||
lw t1, 0x0(t0)
|
||||
addi t2,t1,1
|
||||
sw t2, 0x0(t0)
|
||||
|
||||
/* If reached here from another low priority ISR, skip stack pushing to TCB */
|
||||
bne t1,zero, already_on_handler
|
||||
|
||||
/* Otherwise, save current sp, and use the isr stack from here */
|
||||
lw t0, pxCurrentTCB
|
||||
sw sp, 0x0(t0)
|
||||
lw sp, xIsrStackTop
|
||||
|
||||
already_on_handler:
|
||||
/* Before dispatch c handler, restore interrupt to enable nested intr */
|
||||
csrr s1, mcause
|
||||
csrr s2, mstatus
|
||||
@@ -278,29 +261,13 @@ already_on_handler:
|
||||
sw s3, 0(t0)
|
||||
fence
|
||||
|
||||
/* may skip RTOS aware interrupt since scheduler was not started */
|
||||
lw t1, uxSchedulerRunning
|
||||
beq t1,zero, isr_exit
|
||||
/* Yield to the next task is needed: */
|
||||
mv a0, sp
|
||||
call rtos_int_exit
|
||||
|
||||
/* update nesting interrupts counter */
|
||||
la t0, uxInterruptNesting
|
||||
lw t1, 0x0(t0)
|
||||
/* The next (or current) stack pointer is returned in a0 */
|
||||
mv sp, a0
|
||||
|
||||
/* Already zero, protect against underflow */
|
||||
beq t1, zero, isr_skip_decrement
|
||||
addi t1,t1, -1
|
||||
sw t1, 0x0(t0)
|
||||
|
||||
isr_skip_decrement:
|
||||
/* may still have interrupts pending, skip section below and exit */
|
||||
bne t1,zero,isr_exit
|
||||
|
||||
/* handled all the ISRs and scheduled the next task, take its stack */
|
||||
/* load on sp, then exit. */
|
||||
lw sp, pxCurrentTCB
|
||||
lw sp, 0x0(sp)
|
||||
|
||||
isr_exit:
|
||||
/* restore the rest of the registers */
|
||||
csrw mcause, s1
|
||||
csrw mstatus, s2
|
||||
|
@@ -16,5 +16,6 @@
|
||||
|
||||
#define SOC_CPU_BREAKPOINTS_NUM 8
|
||||
#define SOC_CPU_WATCHPOINTS_NUM 8
|
||||
#define SOC_CPU_HAS_FLEXIBLE_INTC 1
|
||||
|
||||
#define SOC_CPU_WATCHPOINT_SIZE 0x80000000 // bytes
|
||||
|
@@ -43,7 +43,6 @@
|
||||
#include "rmt_caps.h"
|
||||
#include "spi_caps.h"
|
||||
#include "uart_caps.h"
|
||||
#include "int_caps.h"
|
||||
|
||||
/*-------------------------- TOUCH SENSOR CAPS -------------------------------*/
|
||||
#define SOC_TOUCH_SENSOR_NUM (0) /*! No touch sensors on ESP32-C3 */
|
||||
|
Reference in New Issue
Block a user