mirror of
https://github.com/espressif/esp-idf.git
synced 2025-08-03 20:54:32 +02:00
riscv: Add new arch-level component
Changes come from internal branch commit a6723fc
This commit is contained in:
Submodule components/mqtt/esp-mqtt updated: 01594bf118...b9db8d9020
18
components/riscv/CMakeLists.txt
Normal file
18
components/riscv/CMakeLists.txt
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
idf_build_get_property(target IDF_TARGET)
|
||||||
|
if(NOT "${target}" STREQUAL "esp32c3")
|
||||||
|
return()
|
||||||
|
endif()
|
||||||
|
if(BOOTLOADER_BUILD)
|
||||||
|
set(priv_requires soc)
|
||||||
|
else()
|
||||||
|
set(priv_requires soc freertos)
|
||||||
|
set(srcs
|
||||||
|
"interrupt.c"
|
||||||
|
"stdatomic.c"
|
||||||
|
"vectors.S")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
idf_component_register(SRCS "${srcs}"
|
||||||
|
LDFRAGMENTS linker.lf
|
||||||
|
INCLUDE_DIRS "include"
|
||||||
|
PRIV_REQUIRES ${priv_requires})
|
131
components/riscv/include/esp_attr.h
Normal file
131
components/riscv/include/esp_attr.h
Normal file
@@ -0,0 +1,131 @@
|
|||||||
|
// Copyright 2015-2016 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.
|
||||||
|
#ifndef __ESP_ATTR_H__
|
||||||
|
#define __ESP_ATTR_H__
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "sdkconfig.h"
|
||||||
|
|
||||||
|
#define ROMFN_ATTR
|
||||||
|
|
||||||
|
//Normally, the linker script will put all code and rodata in flash,
|
||||||
|
//and all variables in shared RAM. These macros can be used to redirect
|
||||||
|
//particular functions/variables to other memory regions.
|
||||||
|
|
||||||
|
// Forces code into IRAM instead of flash
|
||||||
|
#define IRAM_ATTR _SECTION_ATTR_IMPL(".iram1", __COUNTER__)
|
||||||
|
|
||||||
|
// Forces data into DRAM instead of flash
|
||||||
|
#define DRAM_ATTR _SECTION_ATTR_IMPL(".dram1", __COUNTER__)
|
||||||
|
|
||||||
|
// Forces data to be 4 bytes aligned
|
||||||
|
#define WORD_ALIGNED_ATTR __attribute__((aligned(4)))
|
||||||
|
|
||||||
|
// Forces data to be placed to DMA-capable places
|
||||||
|
#define DMA_ATTR WORD_ALIGNED_ATTR DRAM_ATTR
|
||||||
|
|
||||||
|
// Forces a function to be inlined
|
||||||
|
#define FORCE_INLINE_ATTR static inline __attribute__((always_inline))
|
||||||
|
|
||||||
|
// Forces a string into DRAM instead of flash
|
||||||
|
// Use as ets_printf(DRAM_STR("Hello world!\n"));
|
||||||
|
#define DRAM_STR(str) (__extension__({static const DRAM_ATTR char __c[] = (str); (const char *)&__c;}))
|
||||||
|
|
||||||
|
// Forces code into RTC fast memory. See "docs/deep-sleep-stub.rst"
|
||||||
|
#define RTC_IRAM_ATTR _SECTION_ATTR_IMPL(".rtc.text", __COUNTER__)
|
||||||
|
|
||||||
|
#if CONFIG_SPIRAM_ALLOW_BSS_SEG_EXTERNAL_MEMORY
|
||||||
|
// Forces bss variable into external memory. "
|
||||||
|
#define EXT_RAM_ATTR _SECTION_ATTR_IMPL(".ext_ram.bss", __COUNTER__)
|
||||||
|
#else
|
||||||
|
#define EXT_RAM_ATTR
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Forces data into RTC slow memory. See "docs/deep-sleep-stub.rst"
|
||||||
|
// Any variable marked with this attribute will keep its value
|
||||||
|
// during a deep sleep / wake cycle.
|
||||||
|
#define RTC_DATA_ATTR _SECTION_ATTR_IMPL(".rtc.data", __COUNTER__)
|
||||||
|
|
||||||
|
// Forces read-only data into RTC memory. See "docs/deep-sleep-stub.rst"
|
||||||
|
#define RTC_RODATA_ATTR _SECTION_ATTR_IMPL(".rtc.rodata", __COUNTER__)
|
||||||
|
|
||||||
|
// Allows to place data into RTC_SLOW memory.
|
||||||
|
#define RTC_SLOW_ATTR _SECTION_ATTR_IMPL(".rtc.force_slow", __COUNTER__)
|
||||||
|
|
||||||
|
// Allows to place data into RTC_FAST memory.
|
||||||
|
#define RTC_FAST_ATTR _SECTION_ATTR_IMPL(".rtc.force_fast", __COUNTER__)
|
||||||
|
|
||||||
|
// Forces data into noinit section to avoid initialization after restart.
|
||||||
|
#define __NOINIT_ATTR _SECTION_ATTR_IMPL(".noinit", __COUNTER__)
|
||||||
|
|
||||||
|
// Forces data into RTC slow memory of .noinit section.
|
||||||
|
// Any variable marked with this attribute will keep its value
|
||||||
|
// after restart or during a deep sleep / wake cycle.
|
||||||
|
#define RTC_NOINIT_ATTR _SECTION_ATTR_IMPL(".rtc_noinit", __COUNTER__)
|
||||||
|
|
||||||
|
// Forces to not inline function
|
||||||
|
#define NOINLINE_ATTR __attribute__((noinline))
|
||||||
|
|
||||||
|
// This allows using enum as flags in C++
|
||||||
|
// Format: FLAG_ATTR(flag_enum_t)
|
||||||
|
#ifdef __cplusplus
|
||||||
|
|
||||||
|
// Inline is required here to avoid multiple definition error in linker
|
||||||
|
#define FLAG_ATTR_IMPL(TYPE, INT_TYPE) \
|
||||||
|
FORCE_INLINE_ATTR constexpr TYPE operator~ (TYPE a) { return (TYPE)~(INT_TYPE)a; } \
|
||||||
|
FORCE_INLINE_ATTR constexpr TYPE operator| (TYPE a, TYPE b) { return (TYPE)((INT_TYPE)a | (INT_TYPE)b); } \
|
||||||
|
FORCE_INLINE_ATTR constexpr TYPE operator& (TYPE a, TYPE b) { return (TYPE)((INT_TYPE)a & (INT_TYPE)b); } \
|
||||||
|
FORCE_INLINE_ATTR constexpr TYPE operator^ (TYPE a, TYPE b) { return (TYPE)((INT_TYPE)a ^ (INT_TYPE)b); } \
|
||||||
|
FORCE_INLINE_ATTR constexpr TYPE operator>> (TYPE a, int b) { return (TYPE)((INT_TYPE)a >> b); } \
|
||||||
|
FORCE_INLINE_ATTR constexpr TYPE operator<< (TYPE a, int b) { return (TYPE)((INT_TYPE)a << b); } \
|
||||||
|
FORCE_INLINE_ATTR TYPE& operator|=(TYPE& a, TYPE b) { a = a | b; return a; } \
|
||||||
|
FORCE_INLINE_ATTR TYPE& operator&=(TYPE& a, TYPE b) { a = a & b; return a; } \
|
||||||
|
FORCE_INLINE_ATTR TYPE& operator^=(TYPE& a, TYPE b) { a = a ^ b; return a; } \
|
||||||
|
FORCE_INLINE_ATTR TYPE& operator>>=(TYPE& a, int b) { a >>= b; return a; } \
|
||||||
|
FORCE_INLINE_ATTR TYPE& operator<<=(TYPE& a, int b) { a <<= b; return a; }
|
||||||
|
|
||||||
|
#define FLAG_ATTR_U32(TYPE) FLAG_ATTR_IMPL(TYPE, uint32_t)
|
||||||
|
#define FLAG_ATTR FLAG_ATTR_U32
|
||||||
|
|
||||||
|
#else
|
||||||
|
#define FLAG_ATTR(TYPE)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Implementation for a unique custom section
|
||||||
|
//
|
||||||
|
// This prevents gcc producing "x causes a section type conflict with y"
|
||||||
|
// errors if two variables in the same source file have different linkage (maybe const & non-const) but are placed in the same custom section
|
||||||
|
//
|
||||||
|
// Using unique sections also means --gc-sections can remove unused
|
||||||
|
// data with a custom section type set
|
||||||
|
#define _SECTION_ATTR_IMPL(SECTION, COUNTER) __attribute__((section(SECTION "." _COUNTER_STRINGIFY(COUNTER))))
|
||||||
|
|
||||||
|
#define _COUNTER_STRINGIFY(COUNTER) #COUNTER
|
||||||
|
|
||||||
|
/* Use IDF_DEPRECATED attribute to mark anything deprecated from use in
|
||||||
|
ESP-IDF's own source code, but not deprecated for external users.
|
||||||
|
*/
|
||||||
|
#ifdef IDF_CI_BUILD
|
||||||
|
#define IDF_DEPRECATED(REASON) __attribute__((deprecated(REASON)))
|
||||||
|
#else
|
||||||
|
#define IDF_DEPRECATED(REASON)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#endif /* __ESP_ATTR_H__ */
|
133
components/riscv/include/esp_debug_helpers.h
Normal file
133
components/riscv/include/esp_debug_helpers.h
Normal file
@@ -0,0 +1,133 @@
|
|||||||
|
// 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.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef __ASSEMBLER__
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include "esp_err.h"
|
||||||
|
#include "soc/soc.h"
|
||||||
|
|
||||||
|
#define ESP_WATCHPOINT_LOAD 0x40000000
|
||||||
|
#define ESP_WATCHPOINT_STORE 0x80000000
|
||||||
|
#define ESP_WATCHPOINT_ACCESS 0xC0000000
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @brief Structure used for backtracing
|
||||||
|
*
|
||||||
|
* This structure stores the backtrace information of a particular stack frame
|
||||||
|
* (i.e. the PC and SP). This structure is used iteratively with the
|
||||||
|
* esp_cpu_get_next_backtrace_frame() function to traverse each frame within a
|
||||||
|
* single stack. The next_pc represents the PC of the current frame's caller, thus
|
||||||
|
* a next_pc of 0 indicates that the current frame is the last frame on the stack.
|
||||||
|
*
|
||||||
|
* @note Call esp_backtrace_get_start() to obtain initialization values for
|
||||||
|
* this structure
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
uint32_t pc; /* PC of the current frame */
|
||||||
|
uint32_t sp; /* SP of the current frame */
|
||||||
|
uint32_t next_pc; /* PC of the current frame's caller */
|
||||||
|
} esp_backtrace_frame_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief If an OCD is connected over JTAG. set breakpoint 0 to the given function
|
||||||
|
* address. Do nothing otherwise.
|
||||||
|
* @param fn Pointer to the target breakpoint position
|
||||||
|
*/
|
||||||
|
void esp_set_breakpoint_if_jtag(void *fn);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set a watchpoint to break/panic when a certain memory range is accessed.
|
||||||
|
*
|
||||||
|
* @param no Watchpoint number. On the ESP32, this can be 0 or 1.
|
||||||
|
* @param adr Base address to watch
|
||||||
|
* @param size Size of the region, starting at the base address, to watch. Must
|
||||||
|
* be one of 2^n, with n in [0..6].
|
||||||
|
* @param flags One of ESP_WATCHPOINT_* flags
|
||||||
|
*
|
||||||
|
* @return ESP_ERR_INVALID_ARG on invalid arg, ESP_OK otherwise
|
||||||
|
*
|
||||||
|
* @warning The ESP32 watchpoint hardware watches a region of bytes by effectively
|
||||||
|
* masking away the lower n bits for a region with size 2^n. If adr does
|
||||||
|
* not have zero for these lower n bits, you may not be watching the
|
||||||
|
* region you intended.
|
||||||
|
*/
|
||||||
|
esp_err_t esp_set_watchpoint(int no, void *adr, int size, int flags);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Clear a watchpoint
|
||||||
|
*
|
||||||
|
* @param no Watchpoint to clear
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
void esp_clear_watchpoint(int no);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the first frame of the current stack's backtrace
|
||||||
|
*
|
||||||
|
* Given the following function call flow (B -> A -> X -> esp_backtrace_get_start),
|
||||||
|
* this function will do the following.
|
||||||
|
* - Flush CPU registers and window frames onto the current stack
|
||||||
|
* - Return PC and SP of function A (i.e. start of the stack's backtrace)
|
||||||
|
* - Return PC of function B (i.e. next_pc)
|
||||||
|
*
|
||||||
|
* @note This function is implemented in assembly
|
||||||
|
*
|
||||||
|
* @param[out] pc PC of the first frame in the backtrace
|
||||||
|
* @param[out] sp SP of the first frame in the backtrace
|
||||||
|
* @param[out] next_pc PC of the first frame's caller
|
||||||
|
*/
|
||||||
|
extern void esp_backtrace_get_start(uint32_t *pc, uint32_t *sp, uint32_t *next_pc);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the next frame on a stack for backtracing
|
||||||
|
*
|
||||||
|
* Given a stack frame(i), this function will obtain the next stack frame(i-1)
|
||||||
|
* on the same call stack (i.e. the caller of frame(i)). This function is meant to be
|
||||||
|
* called iteratively when doing a backtrace.
|
||||||
|
*
|
||||||
|
* Entry Conditions: Frame structure containing valid SP and next_pc
|
||||||
|
* Exit Conditions:
|
||||||
|
* - Frame structure updated with SP and PC of frame(i-1). next_pc now points to frame(i-2).
|
||||||
|
* - If a next_pc of 0 is returned, it indicates that frame(i-1) is last frame on the stack
|
||||||
|
*
|
||||||
|
* @param[inout] frame Pointer to frame structure
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* - True if the SP and PC of the next frame(i-1) are sane
|
||||||
|
* - False otherwise
|
||||||
|
*/
|
||||||
|
bool esp_backtrace_get_next_frame(esp_backtrace_frame_t *frame);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Print the backtrace of the current stack
|
||||||
|
*
|
||||||
|
* @param depth The maximum number of stack frames to print (should be > 0)
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* - ESP_OK Backtrace successfully printed to completion or to depth limit
|
||||||
|
* - ESP_FAIL Backtrace is corrupted
|
||||||
|
*/
|
||||||
|
esp_err_t esp_backtrace_print(int depth);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
135
components/riscv/include/riscv/csr.h
Normal file
135
components/riscv/include/riscv/csr.h
Normal file
@@ -0,0 +1,135 @@
|
|||||||
|
// Copyright (c) 2013, The Regents of the University of California (Regents).
|
||||||
|
// Copyright (c) 2018-2019, The libfemto authors
|
||||||
|
// Copyright (c) 2020 Espressif Systems (Shanghai) PTE LTD
|
||||||
|
// All Rights Reserved.
|
||||||
|
|
||||||
|
// Redistribution and use in source and binary forms, with or without
|
||||||
|
// modification, are permitted provided that the following conditions are met:
|
||||||
|
// 1. Redistributions of source code must retain the above copyright
|
||||||
|
// notice, this list of conditions and the following disclaimer.
|
||||||
|
// 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
// notice, this list of conditions and the following disclaimer in the
|
||||||
|
// documentation and/or other materials provided with the distribution.
|
||||||
|
// 3. Neither the name of the Regents nor the
|
||||||
|
// names of its contributors may be used to endorse or promote products
|
||||||
|
// derived from this software without specific prior written permission.
|
||||||
|
|
||||||
|
// IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT,
|
||||||
|
// SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, ARISING
|
||||||
|
// OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF REGENTS HAS
|
||||||
|
// BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
|
// REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||||
|
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||||
|
// PURPOSE. THE SOFTWARE AND ACCOMPANYING DOCUMENTATION, IF ANY, PROVIDED
|
||||||
|
// HEREUNDER IS PROVIDED "AS IS". REGENTS HAS NO OBLIGATION TO PROVIDE
|
||||||
|
// MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <sys/param.h>
|
||||||
|
#include "encoding.h"
|
||||||
|
|
||||||
|
/********************************************************
|
||||||
|
Physical Memory Protection (PMP) register fields
|
||||||
|
(privileged spec)
|
||||||
|
********************************************************/
|
||||||
|
|
||||||
|
/* Value of pmpcfg0 CSR. Note this macro is only needed for calculations like (CSR_PMPCFG0 + 1), which must
|
||||||
|
still be constant at compile time. Use the assembler name pmpcfg0, pmpcfg1, pmpcfg2, etc. in other cases */
|
||||||
|
#define CSR_PMPCFG0 0x3A0
|
||||||
|
|
||||||
|
/* Value of pmpaddr0 CSR. Note, as above, this macro is only needed for calculations and the assembler names
|
||||||
|
pmpaddr0, pmpaddr1, pmpaddr2, etc should be used otherwise. */
|
||||||
|
#define CSR_PMPADDR0 0x3B0
|
||||||
|
|
||||||
|
/* Generate the PMP address field value when PMPCFG.A == NAPOT
|
||||||
|
|
||||||
|
START & END should be calculated at compile time. The size of the region
|
||||||
|
(END-START) must be a power of 2 size, and START must be aligned to this
|
||||||
|
size.
|
||||||
|
|
||||||
|
Note: this value must be right-shifted PMP_SHIFT when written to the PMPADDR
|
||||||
|
register. The PMP_ENTRY_SET macro will do this.
|
||||||
|
*/
|
||||||
|
#define PMPADDR_NAPOT(START, END) ({ \
|
||||||
|
_Static_assert(__builtin_popcount((END)-(START)) == 1, "Size must be a power of 2"); \
|
||||||
|
_Static_assert((START) % ((END)-(START)) == 0, "Start must be aligned to size"); \
|
||||||
|
(((START)) | (((END)-(START)-1)>>1)); \
|
||||||
|
})
|
||||||
|
|
||||||
|
#define PMPADDR_ALL 0xFFFFFFFF
|
||||||
|
|
||||||
|
|
||||||
|
/* Set a PMP entry.
|
||||||
|
|
||||||
|
- ENTRY is number of the PMP entry to set. This must be a compile-time constant because it's used to
|
||||||
|
generate specific assembly instructions.
|
||||||
|
- ADDR is the address to write to the PMPADDRx register. Note this is the unshifted address.
|
||||||
|
- CFG is the configuration value to write to the correct CFG entry register. Note that
|
||||||
|
the macro only sets bits in the CFG register, so it sould be zeroed already.
|
||||||
|
*/
|
||||||
|
#define PMP_ENTRY_SET(ENTRY, ADDR, CFG) do { \
|
||||||
|
RV_WRITE_CSR((CSR_PMPADDR0) + (ENTRY), (ADDR) >> (PMP_SHIFT)); \
|
||||||
|
RV_SET_CSR((CSR_PMPCFG0) + (ENTRY)/4, ((CFG)&0xFF) << (ENTRY%4)*8); \
|
||||||
|
} while(0)
|
||||||
|
|
||||||
|
/********************************************************
|
||||||
|
Trigger Module register fields (Debug specification)
|
||||||
|
********************************************************/
|
||||||
|
|
||||||
|
/* tcontrol CSRs not recognized by toolchain currently */
|
||||||
|
#define CSR_TCONTROL 0x7a5
|
||||||
|
#define CSR_TDATA1 0x7a1
|
||||||
|
|
||||||
|
#define TCONTROL_MTE (1<<3) /*R/W, Current M mode trigger enable bit*/
|
||||||
|
|
||||||
|
#define TDATA1_LOAD (1<<0) /*R/W,Fire trigger on load address match*/
|
||||||
|
#define TDATA1_STORE (1<<1) /*R/W,Fire trigger on store address mat*/
|
||||||
|
#define TDATA1_EXECUTE (1<<2) /*R/W,Fire trigger on instruction fetch address match*/
|
||||||
|
#define TDATA1_USER (1<<3) /*R/W,allow trigger to be fired in user mode*/
|
||||||
|
#define TDATA1_MACHINE (1<<6) /*R/W,Allow trigger to be fired while hart is executing in machine mode*/
|
||||||
|
#define TDATA1_MATCH
|
||||||
|
#define TDATA1_MATCH_V (0xF) /*R/W,Address match type :0 : Exact byte match 1 : NAPOT range match */
|
||||||
|
#define TDATA1_MATCH_S (7)
|
||||||
|
|
||||||
|
|
||||||
|
/* RISC-V CSR macros
|
||||||
|
* Adapted from https://github.com/michaeljclark/riscv-probe/blob/master/libfemto/include/arch/riscv/machine.h
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define RV_READ_CONST_CSR(reg) ({ unsigned long __tmp; \
|
||||||
|
asm ("csrr %0, " _CSR_STRINGIFY(reg) : "=r"(__tmp)); __tmp; })
|
||||||
|
|
||||||
|
#define RV_READ_CSR(reg) ({ unsigned long __tmp; \
|
||||||
|
asm volatile ("csrr %0, " _CSR_STRINGIFY(reg) : "=r"(__tmp)); __tmp; })
|
||||||
|
|
||||||
|
#define RV_WRITE_CSR(reg, val) ({ \
|
||||||
|
asm volatile ("csrw " _CSR_STRINGIFY(reg) ", %0" :: "rK"(val)); })
|
||||||
|
|
||||||
|
#define RV_SWAP_CSR(reg, val) ({ unsigned long __tmp; \
|
||||||
|
asm volatile ("csrrw %0, " _CSR_STRINGIFY(reg) ", %1" : "=r"(__tmp) : "rK"(val)); __tmp; })
|
||||||
|
|
||||||
|
/* Note: this uses the atomic read-and-set instruction so possible to read the old CSR value as a result */
|
||||||
|
#define RV_SET_CSR(reg, bit) ({ unsigned long __tmp; \
|
||||||
|
asm volatile ("csrrs %0, " _CSR_STRINGIFY(reg) ", %1" : "=r"(__tmp) : "rK"(bit)); __tmp; })
|
||||||
|
|
||||||
|
/* Note: this uses the atomic read-and-clear instruction so possible to read the old CSR value as a result */
|
||||||
|
#define RV_CLEAR_CSR(reg, bit) ({ unsigned long __tmp; \
|
||||||
|
asm volatile ("csrrc %0, " _CSR_STRINGIFY(reg) ", %1" : "=r"(__tmp) : "rK"(bit)); __tmp; })
|
||||||
|
|
||||||
|
#define RV_SET_CSR_FIELD(_r, _f, _v) ({ (RV_WRITE_CSR((_r),((RV_READ_CSR(_r) & ~((_f##_V) << (_f##_S)))|(((_v) & (_f##_V))<<(_f##_S)))));})
|
||||||
|
#define RV_CLEAR_CSR_FIELD(_r, _f) ({ (RV_WRITE_CSR((_r),(RV_READ_CSR(_r) & ~((_f##_V) << (_f##_S)))));})
|
||||||
|
|
||||||
|
#define _CSR_STRINGIFY(REG) #REG /* needed so the 'reg' argument can be a macro or a register name */
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
227
components/riscv/include/riscv/encoding.h
Normal file
227
components/riscv/include/riscv/encoding.h
Normal file
@@ -0,0 +1,227 @@
|
|||||||
|
/* Copyright (c) 2010-2017, The Regents of the University of California
|
||||||
|
(Regents). All Rights Reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions are met:
|
||||||
|
1. Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer in the
|
||||||
|
documentation and/or other materials provided with the distribution.
|
||||||
|
3. Neither the name of the Regents nor the
|
||||||
|
names of its contributors may be used to endorse or promote products
|
||||||
|
derived from this software without specific prior written permission.
|
||||||
|
|
||||||
|
IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT,
|
||||||
|
SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, ARISING
|
||||||
|
OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF REGENTS HAS
|
||||||
|
BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
|
REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||||
|
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||||
|
PURPOSE. THE SOFTWARE AND ACCOMPANYING DOCUMENTATION, IF ANY, PROVIDED
|
||||||
|
HEREUNDER IS PROVIDED "AS IS". REGENTS HAS NO OBLIGATION TO PROVIDE
|
||||||
|
MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Adapted from https://github.com/riscv/riscv-opcodes/blob/master/encoding.h */
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
|
||||||
|
#define MSTATUS_UIE 0x00000001
|
||||||
|
#define MSTATUS_SIE 0x00000002
|
||||||
|
#define MSTATUS_HIE 0x00000004
|
||||||
|
#define MSTATUS_MIE 0x00000008
|
||||||
|
#define MSTATUS_UPIE 0x00000010
|
||||||
|
#define MSTATUS_SPIE 0x00000020
|
||||||
|
#define MSTATUS_HPIE 0x00000040
|
||||||
|
#define MSTATUS_MPIE 0x00000080
|
||||||
|
#define MSTATUS_SPP 0x00000100
|
||||||
|
#define MSTATUS_VS 0x00000600
|
||||||
|
#define MSTATUS_MPP 0x00001800
|
||||||
|
#define MSTATUS_FS 0x00006000
|
||||||
|
#define MSTATUS_XS 0x00018000
|
||||||
|
#define MSTATUS_MPRV 0x00020000
|
||||||
|
#define MSTATUS_SUM 0x00040000
|
||||||
|
#define MSTATUS_MXR 0x00080000
|
||||||
|
#define MSTATUS_TVM 0x00100000
|
||||||
|
#define MSTATUS_TW 0x00200000
|
||||||
|
#define MSTATUS_TSR 0x00400000
|
||||||
|
#define MSTATUS32_SD 0x80000000
|
||||||
|
#define MSTATUS_UXL 0x0000000300000000
|
||||||
|
#define MSTATUS_SXL 0x0000000C00000000
|
||||||
|
#define MSTATUS64_SD 0x8000000000000000
|
||||||
|
|
||||||
|
#define SSTATUS_UIE 0x00000001
|
||||||
|
#define SSTATUS_SIE 0x00000002
|
||||||
|
#define SSTATUS_UPIE 0x00000010
|
||||||
|
#define SSTATUS_SPIE 0x00000020
|
||||||
|
#define SSTATUS_SPP 0x00000100
|
||||||
|
#define SSTATUS_VS 0x00000600
|
||||||
|
#define SSTATUS_FS 0x00006000
|
||||||
|
#define SSTATUS_XS 0x00018000
|
||||||
|
#define SSTATUS_SUM 0x00040000
|
||||||
|
#define SSTATUS_MXR 0x00080000
|
||||||
|
#define SSTATUS32_SD 0x80000000
|
||||||
|
#define SSTATUS_UXL 0x0000000300000000
|
||||||
|
#define SSTATUS64_SD 0x8000000000000000
|
||||||
|
|
||||||
|
#define USTATUS_UIE 0x00000001
|
||||||
|
#define USTATUS_UPIE 0x00000010
|
||||||
|
|
||||||
|
#define DCSR_XDEBUGVER (3U<<30)
|
||||||
|
#define DCSR_NDRESET (1<<29)
|
||||||
|
#define DCSR_FULLRESET (1<<28)
|
||||||
|
#define DCSR_EBREAKM (1<<15)
|
||||||
|
#define DCSR_EBREAKH (1<<14)
|
||||||
|
#define DCSR_EBREAKS (1<<13)
|
||||||
|
#define DCSR_EBREAKU (1<<12)
|
||||||
|
#define DCSR_STOPCYCLE (1<<10)
|
||||||
|
#define DCSR_STOPTIME (1<<9)
|
||||||
|
#define DCSR_CAUSE (7<<6)
|
||||||
|
#define DCSR_DEBUGINT (1<<5)
|
||||||
|
#define DCSR_HALT (1<<3)
|
||||||
|
#define DCSR_STEP (1<<2)
|
||||||
|
#define DCSR_PRV (3<<0)
|
||||||
|
|
||||||
|
#define DCSR_CAUSE_NONE 0
|
||||||
|
#define DCSR_CAUSE_SWBP 1
|
||||||
|
#define DCSR_CAUSE_HWBP 2
|
||||||
|
#define DCSR_CAUSE_DEBUGINT 3
|
||||||
|
#define DCSR_CAUSE_STEP 4
|
||||||
|
#define DCSR_CAUSE_HALT 5
|
||||||
|
#define DCSR_CAUSE_GROUP 6
|
||||||
|
|
||||||
|
#define MCONTROL_TYPE(xlen) (0xfULL<<((xlen)-4))
|
||||||
|
#define MCONTROL_DMODE(xlen) (1ULL<<((xlen)-5))
|
||||||
|
#define MCONTROL_MASKMAX(xlen) (0x3fULL<<((xlen)-11))
|
||||||
|
|
||||||
|
#define MCONTROL_SELECT (1<<19)
|
||||||
|
#define MCONTROL_TIMING (1<<18)
|
||||||
|
#define MCONTROL_ACTION (0x3f<<12)
|
||||||
|
#define MCONTROL_CHAIN (1<<11)
|
||||||
|
#define MCONTROL_MATCH (0xf<<7)
|
||||||
|
#define MCONTROL_M (1<<6)
|
||||||
|
#define MCONTROL_H (1<<5)
|
||||||
|
#define MCONTROL_S (1<<4)
|
||||||
|
#define MCONTROL_U (1<<3)
|
||||||
|
#define MCONTROL_EXECUTE (1<<2)
|
||||||
|
#define MCONTROL_STORE (1<<1)
|
||||||
|
#define MCONTROL_LOAD (1<<0)
|
||||||
|
|
||||||
|
#define MCONTROL_TYPE_NONE 0
|
||||||
|
#define MCONTROL_TYPE_MATCH 2
|
||||||
|
|
||||||
|
#define MCONTROL_ACTION_DEBUG_EXCEPTION 0
|
||||||
|
#define MCONTROL_ACTION_DEBUG_MODE 1
|
||||||
|
#define MCONTROL_ACTION_TRACE_START 2
|
||||||
|
#define MCONTROL_ACTION_TRACE_STOP 3
|
||||||
|
#define MCONTROL_ACTION_TRACE_EMIT 4
|
||||||
|
|
||||||
|
#define MCONTROL_MATCH_EQUAL 0
|
||||||
|
#define MCONTROL_MATCH_NAPOT 1
|
||||||
|
#define MCONTROL_MATCH_GE 2
|
||||||
|
#define MCONTROL_MATCH_LT 3
|
||||||
|
#define MCONTROL_MATCH_MASK_LOW 4
|
||||||
|
#define MCONTROL_MATCH_MASK_HIGH 5
|
||||||
|
|
||||||
|
#define MIP_USIP (1 << IRQ_U_SOFT)
|
||||||
|
#define MIP_SSIP (1 << IRQ_S_SOFT)
|
||||||
|
#define MIP_HSIP (1 << IRQ_H_SOFT)
|
||||||
|
#define MIP_MSIP (1 << IRQ_M_SOFT)
|
||||||
|
#define MIP_UTIP (1 << IRQ_U_TIMER)
|
||||||
|
#define MIP_STIP (1 << IRQ_S_TIMER)
|
||||||
|
#define MIP_HTIP (1 << IRQ_H_TIMER)
|
||||||
|
#define MIP_MTIP (1 << IRQ_M_TIMER)
|
||||||
|
#define MIP_UEIP (1 << IRQ_U_EXT)
|
||||||
|
#define MIP_SEIP (1 << IRQ_S_EXT)
|
||||||
|
#define MIP_HEIP (1 << IRQ_H_EXT)
|
||||||
|
#define MIP_MEIP (1 << IRQ_M_EXT)
|
||||||
|
|
||||||
|
#define SIP_SSIP MIP_SSIP
|
||||||
|
#define SIP_STIP MIP_STIP
|
||||||
|
|
||||||
|
#define PRV_U 0
|
||||||
|
#define PRV_S 1
|
||||||
|
#define PRV_H 2
|
||||||
|
#define PRV_M 3
|
||||||
|
|
||||||
|
#define SATP32_MODE 0x80000000
|
||||||
|
#define SATP32_ASID 0x7FC00000
|
||||||
|
#define SATP32_PPN 0x003FFFFF
|
||||||
|
#define SATP64_MODE 0xF000000000000000
|
||||||
|
#define SATP64_ASID 0x0FFFF00000000000
|
||||||
|
#define SATP64_PPN 0x00000FFFFFFFFFFF
|
||||||
|
|
||||||
|
#define SATP_MODE_OFF 0
|
||||||
|
#define SATP_MODE_SV32 1
|
||||||
|
#define SATP_MODE_SV39 8
|
||||||
|
#define SATP_MODE_SV48 9
|
||||||
|
#define SATP_MODE_SV57 10
|
||||||
|
#define SATP_MODE_SV64 11
|
||||||
|
|
||||||
|
#define PMP_R 0x01
|
||||||
|
#define PMP_W 0x02
|
||||||
|
#define PMP_X 0x04
|
||||||
|
#define PMP_A 0x18
|
||||||
|
#define PMP_L 0x80
|
||||||
|
#define PMP_SHIFT 2
|
||||||
|
|
||||||
|
#define PMP_TOR 0x08
|
||||||
|
#define PMP_NA4 0x10
|
||||||
|
#define PMP_NAPOT 0x18
|
||||||
|
|
||||||
|
#define IRQ_U_SOFT 0
|
||||||
|
#define IRQ_S_SOFT 1
|
||||||
|
#define IRQ_H_SOFT 2
|
||||||
|
#define IRQ_M_SOFT 3
|
||||||
|
#define IRQ_U_TIMER 4
|
||||||
|
#define IRQ_S_TIMER 5
|
||||||
|
#define IRQ_H_TIMER 6
|
||||||
|
#define IRQ_M_TIMER 7
|
||||||
|
#define IRQ_U_EXT 8
|
||||||
|
#define IRQ_S_EXT 9
|
||||||
|
#define IRQ_H_EXT 10
|
||||||
|
#define IRQ_M_EXT 11
|
||||||
|
#define IRQ_COP 12
|
||||||
|
#define IRQ_HOST 13
|
||||||
|
|
||||||
|
#define DEFAULT_RSTVEC 0x00001000
|
||||||
|
#define CLINT_BASE 0x02000000
|
||||||
|
#define CLINT_SIZE 0x000c0000
|
||||||
|
#define EXT_IO_BASE 0x40000000
|
||||||
|
#define DRAM_BASE 0x80000000
|
||||||
|
|
||||||
|
/* page table entry (PTE) fields */
|
||||||
|
#define PTE_V 0x001 /* Valid */
|
||||||
|
#define PTE_R 0x002 /* Read */
|
||||||
|
#define PTE_W 0x004 /* Write */
|
||||||
|
#define PTE_X 0x008 /* Execute */
|
||||||
|
#define PTE_U 0x010 /* User */
|
||||||
|
#define PTE_G 0x020 /* Global */
|
||||||
|
#define PTE_A 0x040 /* Accessed */
|
||||||
|
#define PTE_D 0x080 /* Dirty */
|
||||||
|
#define PTE_SOFT 0x300 /* Reserved for Software */
|
||||||
|
|
||||||
|
#define PTE_PPN_SHIFT 10
|
||||||
|
|
||||||
|
#define PTE_TABLE(PTE) (((PTE) & (PTE_V | PTE_R | PTE_W | PTE_X)) == PTE_V)
|
||||||
|
|
||||||
|
#ifdef __riscv
|
||||||
|
|
||||||
|
#if __riscv_xlen == 64
|
||||||
|
# define MSTATUS_SD MSTATUS64_SD
|
||||||
|
# define SSTATUS_SD SSTATUS64_SD
|
||||||
|
# define RISCV_PGLEVEL_BITS 9
|
||||||
|
# define SATP_MODE SATP64_MODE
|
||||||
|
#else
|
||||||
|
# define MSTATUS_SD MSTATUS32_SD
|
||||||
|
# define SSTATUS_SD SSTATUS32_SD
|
||||||
|
# define RISCV_PGLEVEL_BITS 10
|
||||||
|
# define SATP_MODE SATP32_MODE
|
||||||
|
#endif
|
||||||
|
#define RISCV_PGSHIFT 12
|
||||||
|
#define RISCV_PGSIZE (1 << RISCV_PGSHIFT)
|
||||||
|
|
||||||
|
#endif // __riscv
|
115
components/riscv/include/riscv/interrupt.h
Normal file
115
components/riscv/include/riscv/interrupt.h
Normal file
@@ -0,0 +1,115 @@
|
|||||||
|
// 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.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
enum intr_type {
|
||||||
|
INTR_TYPE_LEVEL = 0,
|
||||||
|
INTR_TYPE_EDGE
|
||||||
|
};
|
||||||
|
/*************************** Software interrupt dispatcher ***************************/
|
||||||
|
|
||||||
|
/** Callback type of the interrupt handler */
|
||||||
|
typedef void (*intr_handler_t)(void*);
|
||||||
|
|
||||||
|
/** Set the interrupt handler function for the given CPU interrupt
|
||||||
|
* @param rv_int_num CPU interrupt number
|
||||||
|
* @param fn Handler function
|
||||||
|
* @param arg Handler argument
|
||||||
|
*/
|
||||||
|
void intr_handler_set(int rv_int_num, intr_handler_t fn, void* arg);
|
||||||
|
|
||||||
|
/** Get the interrupt handler function for the given CPU interrupt
|
||||||
|
*
|
||||||
|
*@return interrupt handler registered for a particular interrupt number, or NULL otherwise
|
||||||
|
*/
|
||||||
|
intr_handler_t intr_handler_get(int rv_int_num);
|
||||||
|
|
||||||
|
/** Get the interrupt handler argument associated with the given CPU interrupt
|
||||||
|
*
|
||||||
|
*@return interrupt handler argument for a particular interrupt number, or NULL otherwise
|
||||||
|
*/
|
||||||
|
void *intr_handler_get_arg(int rv_int_num);
|
||||||
|
|
||||||
|
/*************************** Interrupt matrix ***************************/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* this function will be removed in later, please use `intr_matrix_set` instead
|
||||||
|
* Route the peripheral interrupt signal to the CPU
|
||||||
|
* @param periph_intr_source Peripheral interrupt number, one of ETS_XXX_SOURCE
|
||||||
|
* @param rv_int_num CPU interrupt number
|
||||||
|
*/
|
||||||
|
void intr_matrix_route(int periph_intr_source, int rv_int_num);
|
||||||
|
|
||||||
|
/*************************** ESP-RV Interrupt Controller ***************************/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Enable interrupts from interrupt controller.
|
||||||
|
*
|
||||||
|
* @param uint32_t unmask, unmask bits for interrupts, each bit for an interrupt
|
||||||
|
*
|
||||||
|
* return none
|
||||||
|
*/
|
||||||
|
void esprv_intc_int_enable(uint32_t unmask);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Disable interrupts from interrupt controller.
|
||||||
|
*
|
||||||
|
* @param uint32_t mask, mask bits for interrupts, each bit for an interrupt
|
||||||
|
*
|
||||||
|
* return none
|
||||||
|
*/
|
||||||
|
void esprv_intc_int_disable(uint32_t mask);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set interrupt type, level or edge
|
||||||
|
*
|
||||||
|
* @param int intr_num, interrupt number
|
||||||
|
*
|
||||||
|
* @param enum intr_type type, interrupt type, the level interrupt
|
||||||
|
can be cleared automatically once the interrupt source cleared, the edge interrupt should be clear by software after handled
|
||||||
|
*
|
||||||
|
* return none
|
||||||
|
*/
|
||||||
|
void esprv_intc_int_set_type(int intr_num, enum intr_type type);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set interrupt priority in the interrupt controller
|
||||||
|
* @param rv_int_num CPU interrupt number
|
||||||
|
* @param priority Interrupt priority level, 1 to 7
|
||||||
|
*/
|
||||||
|
void esprv_intc_int_set_priority(int rv_int_num, int priority);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set interrupt priority threshold.
|
||||||
|
* Interrupts with priority levels lower than the threshold are masked.
|
||||||
|
*
|
||||||
|
* @param priority_threshold Interrupt priority threshold, 0 to 7
|
||||||
|
*/
|
||||||
|
void esprv_intc_set_threshold(int priority_threshold);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get interrupt unmask
|
||||||
|
* @param none
|
||||||
|
* @return uint32_t interrupt unmask
|
||||||
|
*/
|
||||||
|
uint32_t esprv_intc_get_interrupt_unmask(void);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
45
components/riscv/include/riscv/riscv_interrupts.h
Normal file
45
components/riscv/include/riscv/riscv_interrupts.h
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
// 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.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enable CPU interrupt
|
||||||
|
* @param rv_int_num CPU interrupt number
|
||||||
|
*/
|
||||||
|
void riscv_interrupt_enable(int rv_int_num);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Disable CPU interrupt
|
||||||
|
* @param rv_int_num CPU interrupt number
|
||||||
|
*/
|
||||||
|
void riscv_interrupt_disable(int rv_int_num);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Globally enable CPU interrupts
|
||||||
|
*/
|
||||||
|
void riscv_global_interrupts_enable(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Globally disable CPU interrupts
|
||||||
|
*/
|
||||||
|
void riscv_global_interrupts_disable(void);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
95
components/riscv/include/riscv/rvruntime-frames.h
Normal file
95
components/riscv/include/riscv/rvruntime-frames.h
Normal file
@@ -0,0 +1,95 @@
|
|||||||
|
#ifndef __RVRUNTIME_FRAMES_H__
|
||||||
|
#define __RVRUNTIME_FRAMES_H__
|
||||||
|
|
||||||
|
/* Align a value up to nearest n-byte boundary, where n is a power of 2. */
|
||||||
|
#define ALIGNUP(n, val) (((val) + (n)-1) & -(n))
|
||||||
|
|
||||||
|
#ifdef STRUCT_BEGIN
|
||||||
|
#undef STRUCT_BEGIN
|
||||||
|
#undef STRUCT_FIELD
|
||||||
|
#undef STRUCT_AFIELD
|
||||||
|
#undef STRUCT_END
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(_ASMLANGUAGE) || defined(__ASSEMBLER__)
|
||||||
|
|
||||||
|
#define STRUCT_BEGIN .pushsection .text; .struct 0
|
||||||
|
#define STRUCT_FIELD(ctype,size,asname,name) asname: .space size
|
||||||
|
#define STRUCT_AFIELD(ctype,size,asname,name,n) asname: .space (size)*(n)
|
||||||
|
#define STRUCT_END(sname) sname##Size:; .popsection
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
#define STRUCT_BEGIN typedef struct {
|
||||||
|
#define STRUCT_FIELD(ctype,size,asname,name) ctype name;
|
||||||
|
#define STRUCT_AFIELD(ctype,size,asname,name,n) ctype name[n];
|
||||||
|
#define STRUCT_END(sname) } sname;
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
INTERRUPT/EXCEPTION STACK FRAME FOR A EXCEPTION OR NESTED INTERRUPT
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
STRUCT_BEGIN
|
||||||
|
STRUCT_FIELD (long, 4, RV_STK_MEPC, mepc) /* Machine Exception Program Counter */
|
||||||
|
STRUCT_FIELD (long, 4, RV_STK_RA, ra) /* Return address */
|
||||||
|
STRUCT_FIELD (long, 4, RV_STK_SP, sp) /* Stack pointer */
|
||||||
|
STRUCT_FIELD (long, 4, RV_STK_GP, gp) /* Global pointer */
|
||||||
|
STRUCT_FIELD (long, 4, RV_STK_TP, tp) /* Thread pointer */
|
||||||
|
STRUCT_FIELD (long, 4, RV_STK_T0, t0) /* Temporary/alternate link register */
|
||||||
|
STRUCT_FIELD (long, 4, RV_STK_T1, t1) /* t1-2: Temporaries */
|
||||||
|
STRUCT_FIELD (long, 4, RV_STK_T2, t2)
|
||||||
|
STRUCT_FIELD (long, 4, RV_STK_S0, s0) /* Saved register/frame pointer */
|
||||||
|
STRUCT_FIELD (long, 4, RV_STK_S1, s1) /* Saved register */
|
||||||
|
STRUCT_FIELD (long, 4, RV_STK_A0, a0) /* a0-1: Function arguments/return address */
|
||||||
|
STRUCT_FIELD (long, 4, RV_STK_A1, a1)
|
||||||
|
STRUCT_FIELD (long, 4, RV_STK_A2, a2) /* a2-7: Function arguments */
|
||||||
|
STRUCT_FIELD (long, 4, RV_STK_A3, a3)
|
||||||
|
STRUCT_FIELD (long, 4, RV_STK_A4, a4)
|
||||||
|
STRUCT_FIELD (long, 4, RV_STK_A5, a5)
|
||||||
|
STRUCT_FIELD (long, 4, RV_STK_A6, a6)
|
||||||
|
STRUCT_FIELD (long, 4, RV_STK_A7, a7)
|
||||||
|
STRUCT_FIELD (long, 4, RV_STK_S2, s2) /* s2-11: Saved registers */
|
||||||
|
STRUCT_FIELD (long, 4, RV_STK_S3, s3)
|
||||||
|
STRUCT_FIELD (long, 4, RV_STK_S4, s4)
|
||||||
|
STRUCT_FIELD (long, 4, RV_STK_S5, s5)
|
||||||
|
STRUCT_FIELD (long, 4, RV_STK_S6, s6)
|
||||||
|
STRUCT_FIELD (long, 4, RV_STK_S7, s7)
|
||||||
|
STRUCT_FIELD (long, 4, RV_STK_S8, s8)
|
||||||
|
STRUCT_FIELD (long, 4, RV_STK_S9, s9)
|
||||||
|
STRUCT_FIELD (long, 4, RV_STK_S10, s10)
|
||||||
|
STRUCT_FIELD (long, 4, RV_STK_S11, s11)
|
||||||
|
STRUCT_FIELD (long, 4, RV_STK_T3, t3) /* t3-6: Temporaries */
|
||||||
|
STRUCT_FIELD (long, 4, RV_STK_T4, t4)
|
||||||
|
STRUCT_FIELD (long, 4, RV_STK_T5, t5)
|
||||||
|
STRUCT_FIELD (long, 4, RV_STK_T6, t6)
|
||||||
|
STRUCT_FIELD (long, 4, RV_STK_MSTATUS, mstatus) /* Machine Status */
|
||||||
|
STRUCT_FIELD (long, 4, RV_STK_MTVEC, mtvec) /* Machine Trap-Vector Base Address */
|
||||||
|
STRUCT_FIELD (long, 4, RV_STK_MCAUSE, mcause) /* Machine Trap Cause */
|
||||||
|
STRUCT_FIELD (long, 4, RV_STK_PCCRS, pccrs) /* Performance Counter Counter Registers */
|
||||||
|
STRUCT_FIELD (long, 4, RV_STK_PCER, pcer) /* Performance Counter Enable */
|
||||||
|
STRUCT_FIELD (long, 4, RV_STK_PCMR, pcmr) /* Performance Counter Mode */
|
||||||
|
STRUCT_FIELD (long, 4, RV_STK_HWLP, hwlp) /* Hardware Loop Registers */
|
||||||
|
STRUCT_FIELD (long, 4, RV_STK_PRIVLV, privlv) /* Privilege Level */
|
||||||
|
STRUCT_FIELD (long, 4, RV_STK_UHARTID, uhartid) /* Hardware Thread ID */
|
||||||
|
STRUCT_FIELD (long, 4, RV_STK_MHARTID, mhartid) /* Hardware Thread ID */
|
||||||
|
STRUCT_FIELD (long, 4, RV_STK_DCSR, dcsr) /* Debug Control and Status */
|
||||||
|
STRUCT_FIELD (long, 4, RV_STK_DPC, dpc) /* Debug PC */
|
||||||
|
STRUCT_FIELD (long, 4, RV_STK_INTC_THRESH, intc_thresh)
|
||||||
|
STRUCT_FIELD (long, 4, RV_STK_RESERVED0, reserved0)
|
||||||
|
STRUCT_END(RvExcFrame)
|
||||||
|
|
||||||
|
#if defined(_ASMLANGUAGE) || defined(__ASSEMBLER__)
|
||||||
|
# define RV_STK_SZ1 RvExcFrameSize
|
||||||
|
#else
|
||||||
|
# define RV_STK_SZ1 sizeof(RvExcFrame)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This is the frame size.
|
||||||
|
*/
|
||||||
|
#define RV_STK_FRMSZ (ALIGNUP(0x10, RV_STK_SZ1))
|
||||||
|
|
||||||
|
#endif /* #ifndef __RVRUNTIME_FRAMES_H__ */
|
111
components/riscv/interrupt.c
Normal file
111
components/riscv/interrupt.c
Normal file
@@ -0,0 +1,111 @@
|
|||||||
|
// 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 <stdint.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <assert.h>
|
||||||
|
#include "riscv/interrupt.h"
|
||||||
|
#include "soc/interrupt_reg.h"
|
||||||
|
#include "riscv/csr.h"
|
||||||
|
#include "esp_attr.h"
|
||||||
|
|
||||||
|
#define RV_INT_COUNT 32
|
||||||
|
|
||||||
|
static inline void assert_valid_rv_int_num(int rv_int_num)
|
||||||
|
{
|
||||||
|
assert(rv_int_num != 0 && rv_int_num < RV_INT_COUNT && "Invalid CPU interrupt number");
|
||||||
|
}
|
||||||
|
|
||||||
|
/*************************** Software interrupt dispatcher ***************************/
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
intr_handler_t handler;
|
||||||
|
void *arg;
|
||||||
|
} intr_handler_item_t;
|
||||||
|
|
||||||
|
static intr_handler_item_t s_intr_handlers[32];
|
||||||
|
|
||||||
|
void intr_handler_set(int int_no, intr_handler_t fn, void *arg)
|
||||||
|
{
|
||||||
|
assert_valid_rv_int_num(int_no);
|
||||||
|
|
||||||
|
s_intr_handlers[int_no] = (intr_handler_item_t) {
|
||||||
|
.handler = fn,
|
||||||
|
.arg = arg
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
intr_handler_t intr_handler_get(int rv_int_num)
|
||||||
|
{
|
||||||
|
return s_intr_handlers[rv_int_num].handler;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *intr_handler_get_arg(int rv_int_num)
|
||||||
|
{
|
||||||
|
return s_intr_handlers[rv_int_num].arg;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* called from vectors.S */
|
||||||
|
void _global_interrupt_handler(intptr_t sp, int mcause)
|
||||||
|
{
|
||||||
|
intr_handler_item_t it = s_intr_handlers[mcause];
|
||||||
|
if (it.handler) {
|
||||||
|
(*it.handler)(it.arg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*************************** RISC-V interrupt enable/disable ***************************/
|
||||||
|
|
||||||
|
void intr_matrix_route(int intr_src, int intr_num)
|
||||||
|
{
|
||||||
|
assert(intr_num != 0);
|
||||||
|
|
||||||
|
REG_WRITE(DR_REG_INTERRUPT_BASE + 4 * intr_src, intr_num);
|
||||||
|
}
|
||||||
|
|
||||||
|
void riscv_global_interrupts_enable(void)
|
||||||
|
{
|
||||||
|
RV_SET_CSR(mstatus, MSTATUS_MIE);
|
||||||
|
}
|
||||||
|
|
||||||
|
void riscv_global_interrupts_disable(void)
|
||||||
|
{
|
||||||
|
RV_CLEAR_CSR(mstatus, MSTATUS_MIE);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t esprv_intc_get_interrupt_unmask(void)
|
||||||
|
{
|
||||||
|
return REG_READ(INTERRUPT_CORE0_CPU_INT_ENABLE_REG);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*************************** Exception names. Used in .gdbinit file. ***************************/
|
||||||
|
|
||||||
|
const char *riscv_excp_names[16] __attribute__((used)) = {
|
||||||
|
"misaligned_fetch",
|
||||||
|
"fault_fetch",
|
||||||
|
"illegal_instruction",
|
||||||
|
"breakpoint",
|
||||||
|
"misaligned_load",
|
||||||
|
"fault_load",
|
||||||
|
"misaligned_store",
|
||||||
|
"fault_store",
|
||||||
|
"user_ecall",
|
||||||
|
"supervisor_ecall",
|
||||||
|
"hypervisor_ecall",
|
||||||
|
"machine_ecall",
|
||||||
|
"exec_page_fault",
|
||||||
|
"load_page_fault",
|
||||||
|
"reserved",
|
||||||
|
"store_page_fault"
|
||||||
|
};
|
5
components/riscv/linker.lf
Normal file
5
components/riscv/linker.lf
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
[mapping:riscv]
|
||||||
|
archive: libriscv.a
|
||||||
|
entries:
|
||||||
|
interrupt (noflash_text)
|
||||||
|
vectors (noflash_text)
|
129
components/riscv/stdatomic.c
Normal file
129
components/riscv/stdatomic.c
Normal file
@@ -0,0 +1,129 @@
|
|||||||
|
// 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.
|
||||||
|
|
||||||
|
//replacement for gcc built-in functions
|
||||||
|
|
||||||
|
#include "sdkconfig.h"
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include "freertos/portmacro.h"
|
||||||
|
|
||||||
|
//reserved to measure atomic operation time
|
||||||
|
#define atomic_benchmark_intr_disable()
|
||||||
|
#define atomic_benchmark_intr_restore(STATE)
|
||||||
|
|
||||||
|
// This allows nested interrupts disabling and restoring via local registers or stack.
|
||||||
|
// They can be called from interrupts too.
|
||||||
|
// WARNING: Only applies to current CPU.
|
||||||
|
#define _ATOMIC_ENTER_CRITICAL(void) ({ \
|
||||||
|
unsigned state = portENTER_CRITICAL_NESTED(); \
|
||||||
|
atomic_benchmark_intr_disable(); \
|
||||||
|
state; \
|
||||||
|
})
|
||||||
|
|
||||||
|
#define _ATOMIC_EXIT_CRITICAL(state) do { \
|
||||||
|
atomic_benchmark_intr_restore(state); \
|
||||||
|
portEXIT_CRITICAL_NESTED(state); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define CMP_EXCHANGE(n, type) bool __atomic_compare_exchange_ ## n (type* mem, type* expect, type desired, int success, int failure) \
|
||||||
|
{ \
|
||||||
|
bool ret = false; \
|
||||||
|
unsigned state = _ATOMIC_ENTER_CRITICAL(); \
|
||||||
|
if (*mem == *expect) { \
|
||||||
|
ret = true; \
|
||||||
|
*mem = desired; \
|
||||||
|
} else { \
|
||||||
|
*expect = *mem; \
|
||||||
|
} \
|
||||||
|
_ATOMIC_EXIT_CRITICAL(state); \
|
||||||
|
return ret; \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define FETCH_ADD(n, type) type __atomic_fetch_add_ ## n (type* ptr, type value, int memorder) \
|
||||||
|
{ \
|
||||||
|
unsigned state = _ATOMIC_ENTER_CRITICAL(); \
|
||||||
|
type ret = *ptr; \
|
||||||
|
*ptr = *ptr + value; \
|
||||||
|
_ATOMIC_EXIT_CRITICAL(state); \
|
||||||
|
return ret; \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define FETCH_SUB(n, type) type __atomic_fetch_sub_ ## n (type* ptr, type value, int memorder) \
|
||||||
|
{ \
|
||||||
|
unsigned state = _ATOMIC_ENTER_CRITICAL(); \
|
||||||
|
type ret = *ptr; \
|
||||||
|
*ptr = *ptr - value; \
|
||||||
|
_ATOMIC_EXIT_CRITICAL(state); \
|
||||||
|
return ret; \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define FETCH_AND(n, type) type __atomic_fetch_and_ ## n (type* ptr, type value, int memorder) \
|
||||||
|
{ \
|
||||||
|
unsigned state = _ATOMIC_ENTER_CRITICAL(); \
|
||||||
|
type ret = *ptr; \
|
||||||
|
*ptr = *ptr & value; \
|
||||||
|
_ATOMIC_EXIT_CRITICAL(state); \
|
||||||
|
return ret; \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define FETCH_OR(n, type) type __atomic_fetch_or_ ## n (type* ptr, type value, int memorder) \
|
||||||
|
{ \
|
||||||
|
unsigned state = _ATOMIC_ENTER_CRITICAL(); \
|
||||||
|
type ret = *ptr; \
|
||||||
|
*ptr = *ptr | value; \
|
||||||
|
_ATOMIC_EXIT_CRITICAL(state); \
|
||||||
|
return ret; \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define FETCH_XOR(n, type) type __atomic_fetch_xor_ ## n (type* ptr, type value, int memorder) \
|
||||||
|
{ \
|
||||||
|
unsigned state = _ATOMIC_ENTER_CRITICAL(); \
|
||||||
|
type ret = *ptr; \
|
||||||
|
*ptr = *ptr ^ value; \
|
||||||
|
_ATOMIC_EXIT_CRITICAL(state); \
|
||||||
|
return ret; \
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma GCC diagnostic ignored "-Wbuiltin-declaration-mismatch"
|
||||||
|
|
||||||
|
CMP_EXCHANGE(1, uint8_t)
|
||||||
|
CMP_EXCHANGE(2, uint16_t)
|
||||||
|
CMP_EXCHANGE(4, uint32_t)
|
||||||
|
CMP_EXCHANGE(8, uint64_t)
|
||||||
|
|
||||||
|
FETCH_ADD(1, uint8_t)
|
||||||
|
FETCH_ADD(2, uint16_t)
|
||||||
|
FETCH_ADD(4, uint32_t)
|
||||||
|
FETCH_ADD(8, uint64_t)
|
||||||
|
|
||||||
|
FETCH_SUB(1, uint8_t)
|
||||||
|
FETCH_SUB(2, uint16_t)
|
||||||
|
FETCH_SUB(4, uint32_t)
|
||||||
|
FETCH_SUB(8, uint64_t)
|
||||||
|
|
||||||
|
FETCH_AND(1, uint8_t)
|
||||||
|
FETCH_AND(2, uint16_t)
|
||||||
|
FETCH_AND(4, uint32_t)
|
||||||
|
FETCH_AND(8, uint64_t)
|
||||||
|
|
||||||
|
FETCH_OR(1, uint8_t)
|
||||||
|
FETCH_OR(2, uint16_t)
|
||||||
|
FETCH_OR(4, uint32_t)
|
||||||
|
FETCH_OR(8, uint64_t)
|
||||||
|
|
||||||
|
FETCH_XOR(1, uint8_t)
|
||||||
|
FETCH_XOR(2, uint16_t)
|
||||||
|
FETCH_XOR(4, uint32_t)
|
||||||
|
FETCH_XOR(8, uint64_t)
|
307
components/riscv/vectors.S
Normal file
307
components/riscv/vectors.S
Normal file
@@ -0,0 +1,307 @@
|
|||||||
|
// 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 "soc/soc.h"
|
||||||
|
#include "soc/interrupt_reg.h"
|
||||||
|
|
||||||
|
|
||||||
|
.equ SAVE_REGS, 32
|
||||||
|
.equ CONTEXT_SIZE, (SAVE_REGS * 4)
|
||||||
|
.equ PANIC_REGS, 38
|
||||||
|
.equ PANIC_REGS_SIZE, (PANIC_REGS * 4)
|
||||||
|
|
||||||
|
.altmacro
|
||||||
|
|
||||||
|
.macro lwsp a, b
|
||||||
|
lw \a, ((\b)*4)(sp)
|
||||||
|
.endm
|
||||||
|
|
||||||
|
.macro swsp a, b
|
||||||
|
sw \a, ((\b)*4)(sp)
|
||||||
|
.endm
|
||||||
|
|
||||||
|
|
||||||
|
.macro save_regs
|
||||||
|
addi sp, sp, -CONTEXT_SIZE
|
||||||
|
swsp ra, 1
|
||||||
|
swsp a0, 2
|
||||||
|
swsp a1, 3
|
||||||
|
swsp a2, 4
|
||||||
|
swsp a3, 5
|
||||||
|
swsp a4, 6
|
||||||
|
swsp a5, 7
|
||||||
|
swsp a6, 8
|
||||||
|
swsp a7, 9
|
||||||
|
swsp t0, 10
|
||||||
|
swsp t1, 11
|
||||||
|
swsp t2, 12
|
||||||
|
swsp t3, 13
|
||||||
|
swsp t4, 14
|
||||||
|
swsp t5, 15
|
||||||
|
swsp t6, 16
|
||||||
|
//swsp sp, 17
|
||||||
|
//swsp gp, 18
|
||||||
|
swsp tp, 19
|
||||||
|
swsp s0, 20
|
||||||
|
swsp s1, 21
|
||||||
|
swsp s2, 22
|
||||||
|
swsp s3, 23
|
||||||
|
swsp s4, 24
|
||||||
|
swsp s5, 25
|
||||||
|
swsp s6, 26
|
||||||
|
swsp s7, 27
|
||||||
|
swsp s8, 28
|
||||||
|
swsp s9, 29
|
||||||
|
swsp s10, 30
|
||||||
|
swsp s11, 31
|
||||||
|
.endm
|
||||||
|
|
||||||
|
.macro save_mepc
|
||||||
|
csrr t0, mepc
|
||||||
|
swsp t0, 0
|
||||||
|
.endm
|
||||||
|
|
||||||
|
.macro restore_regs
|
||||||
|
lwsp ra, 1
|
||||||
|
lwsp a0, 2
|
||||||
|
lwsp a1, 3
|
||||||
|
lwsp a2, 4
|
||||||
|
lwsp a3, 5
|
||||||
|
lwsp a4, 6
|
||||||
|
lwsp a5, 7
|
||||||
|
lwsp a6, 8
|
||||||
|
lwsp a7, 9
|
||||||
|
lwsp t0, 10
|
||||||
|
lwsp t1, 11
|
||||||
|
lwsp t2, 12
|
||||||
|
lwsp t3, 13
|
||||||
|
lwsp t4, 14
|
||||||
|
lwsp t5, 15
|
||||||
|
lwsp t6, 16
|
||||||
|
//lwsp sp, 17
|
||||||
|
//lwsp gp, 18
|
||||||
|
lwsp tp, 19
|
||||||
|
lwsp s0, 20
|
||||||
|
lwsp s1, 21
|
||||||
|
lwsp s2, 22
|
||||||
|
lwsp s3, 23
|
||||||
|
lwsp s4, 24
|
||||||
|
lwsp s5, 25
|
||||||
|
lwsp s6, 26
|
||||||
|
lwsp s7, 27
|
||||||
|
lwsp s8, 28
|
||||||
|
lwsp s9, 29
|
||||||
|
lwsp s10, 30
|
||||||
|
lwsp s11, 31
|
||||||
|
addi sp, sp, CONTEXT_SIZE
|
||||||
|
.endm
|
||||||
|
|
||||||
|
.macro restore_mepc
|
||||||
|
lwsp t0, 0
|
||||||
|
csrw mepc, t0
|
||||||
|
.endm
|
||||||
|
|
||||||
|
.global vPortYieldFromISR
|
||||||
|
.global uxInterruptNesting
|
||||||
|
.global uxSchedulerRunning
|
||||||
|
.global xIsrStackTop
|
||||||
|
.global pxCurrentTCB
|
||||||
|
.global _global_interrupt_handler
|
||||||
|
|
||||||
|
.section .exception_vectors.text
|
||||||
|
/* This is the vector table. MTVEC points here.
|
||||||
|
*
|
||||||
|
* Use 4-byte intructions here. 1 instruction = 1 entry of the table.
|
||||||
|
* The CPU jumps to MTVEC (i.e. the first entry) in case of an exception,
|
||||||
|
* and (MTVEC & 0xfffffffc) + (mcause & 0x7fffffff) * 4, in case of an interrupt.
|
||||||
|
*
|
||||||
|
* Note: for our CPU, we need to place this on a 256-byte boundary, as CPU
|
||||||
|
* only uses the 24 MSBs of the MTVEC, i.e. (MTVEC & 0xffffff00).
|
||||||
|
*/
|
||||||
|
|
||||||
|
.balign 0x100
|
||||||
|
.global _vector_table
|
||||||
|
.type _vector_table, @function
|
||||||
|
_vector_table:
|
||||||
|
.option push
|
||||||
|
.option norvc
|
||||||
|
j _panic_handler /* exception handler, entry 0 */
|
||||||
|
.rept 31
|
||||||
|
j _interrupt_handler /* 31 identical entries, all pointing to the interrupt handler */
|
||||||
|
.endr
|
||||||
|
.option pop
|
||||||
|
.size _vector_table, .-_vector_table
|
||||||
|
|
||||||
|
/* Exception handler.*/
|
||||||
|
.global panicHandler
|
||||||
|
.type _panic_handler, @function
|
||||||
|
_panic_handler:
|
||||||
|
addi sp, sp, -PANIC_REGS_SIZE
|
||||||
|
swsp x0, 0
|
||||||
|
swsp x1, 1
|
||||||
|
/* x2 is sp - it will be placed on stack later (after we can use the other registers for computation) */
|
||||||
|
swsp x3, 3
|
||||||
|
swsp x4, 4
|
||||||
|
swsp x5, 5
|
||||||
|
swsp x6, 6
|
||||||
|
swsp x7, 7
|
||||||
|
swsp x8, 8
|
||||||
|
swsp x9, 9
|
||||||
|
swsp x10, 10
|
||||||
|
swsp x11, 11
|
||||||
|
swsp x12, 12
|
||||||
|
swsp x13, 13
|
||||||
|
swsp x14, 14
|
||||||
|
swsp x15, 15
|
||||||
|
swsp x16, 16
|
||||||
|
swsp x17, 17
|
||||||
|
swsp x18, 18
|
||||||
|
swsp x19, 19
|
||||||
|
swsp x20, 20
|
||||||
|
swsp x21, 21
|
||||||
|
swsp x22, 22
|
||||||
|
swsp x23, 23
|
||||||
|
swsp x24, 24
|
||||||
|
swsp x25, 25
|
||||||
|
swsp x26, 26
|
||||||
|
swsp x27, 27
|
||||||
|
swsp x28, 28
|
||||||
|
swsp x29, 29
|
||||||
|
swsp x30, 30
|
||||||
|
swsp x31, 31
|
||||||
|
/* "Undo" the modification already done to the sp (x2) by the panic handler */
|
||||||
|
addi a1, x2, PANIC_REGS_SIZE
|
||||||
|
swsp a1, 2
|
||||||
|
csrr a1, mcause
|
||||||
|
swsp a1, 32
|
||||||
|
csrr a1, mepc
|
||||||
|
swsp a1, 33
|
||||||
|
csrr a1, mhartid
|
||||||
|
swsp a1, 34
|
||||||
|
csrr a1, mstatus
|
||||||
|
swsp a1, 35
|
||||||
|
csrr a1, mtval
|
||||||
|
swsp a1, 36
|
||||||
|
csrr a1, mtvec
|
||||||
|
swsp a1, 37
|
||||||
|
mv a0, sp
|
||||||
|
csrr a1, mcause
|
||||||
|
jal zero, panicHandler
|
||||||
|
/* panicHandler never returns */
|
||||||
|
.size _panic_handler, .-_panic_handler
|
||||||
|
|
||||||
|
/* This is the interrupt handler.
|
||||||
|
* It saves the registers on the stack,
|
||||||
|
* prepares for interrupt nesting,
|
||||||
|
* re-enables the interrupts,
|
||||||
|
* then jumps to the C dispatcher in interrupt.c.
|
||||||
|
*/
|
||||||
|
.global _interrupt_handler
|
||||||
|
.type _interrupt_handler, @function
|
||||||
|
_interrupt_handler:
|
||||||
|
/* entry */
|
||||||
|
save_regs
|
||||||
|
save_mepc
|
||||||
|
|
||||||
|
/* scheduler not enabled, jump directly to ISR handler */
|
||||||
|
lw t0, uxSchedulerRunning
|
||||||
|
beq t0,zero,already_on_handler
|
||||||
|
|
||||||
|
/* increments the ISR nesting count */
|
||||||
|
/* This will work properly when we have nested interrupts */
|
||||||
|
la t0, uxInterruptNesting
|
||||||
|
lw t1, 0x0(t0)
|
||||||
|
addi t2,t1,1
|
||||||
|
sw t2, 0x0(t0)
|
||||||
|
|
||||||
|
/* If reached here from another low-prio 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
|
||||||
|
|
||||||
|
/* Save the interrupt threshold level */
|
||||||
|
la t0, INTERRUPT_CORE0_CPU_INT_THRESH_REG
|
||||||
|
lw s3, 0(t0)
|
||||||
|
|
||||||
|
/* Increase interrupt threshold level */
|
||||||
|
la t2, 0x7fffffff
|
||||||
|
and t1, s1, t2 /* t1 = mcause & mask */
|
||||||
|
slli t1, t1, 2 /* t1 = mcause * 4 */
|
||||||
|
la t2, INTC_INT_PRIO_REG(0)
|
||||||
|
add t1, t2, t1 /* t1 = INTC_INT_PRIO_REG + 4 * mcause */
|
||||||
|
lw t2, 0(t1) /* t2 = INTC_INT_PRIO_REG[mcause] */
|
||||||
|
addi t2, t2, 1 /* t2 = t2 +1 */
|
||||||
|
sw t2, 0(t0) /* INTERRUPT_CORE0_CPU_INT_THRESH_REG = t2 */
|
||||||
|
fence
|
||||||
|
|
||||||
|
la t0, 0x8
|
||||||
|
csrrs t0, mstatus, t0
|
||||||
|
|
||||||
|
/* call the C dispatcher */
|
||||||
|
mv a0, sp /* argument 1, stack pointer */
|
||||||
|
csrr a1, mcause /* argument 2, interrupt number */
|
||||||
|
/* mask off the interrupt flag of mcause */
|
||||||
|
la t0, 0x7fffffff
|
||||||
|
and a1, a1, t0
|
||||||
|
jal _global_interrupt_handler
|
||||||
|
|
||||||
|
/* After dispatch c handler, disable interrupt to make freertos make context switch */
|
||||||
|
|
||||||
|
la t0, 0x8
|
||||||
|
csrrc t0, mstatus, t0
|
||||||
|
|
||||||
|
/* restore the interrupt threshold level */
|
||||||
|
la t0, INTERRUPT_CORE0_CPU_INT_THRESH_REG
|
||||||
|
sw s3, 0(t0)
|
||||||
|
fence
|
||||||
|
|
||||||
|
/* may skip RTOS aware interrupt since scheduler was not started */
|
||||||
|
lw t1, uxSchedulerRunning
|
||||||
|
beq t1,zero, isr_exit
|
||||||
|
|
||||||
|
/* update nesting interrupts counter */
|
||||||
|
la t0, uxInterruptNesting
|
||||||
|
lw t1, 0x0(t0)
|
||||||
|
|
||||||
|
/* Already zero, protect againts 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
|
||||||
|
|
||||||
|
/* handlered 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
|
||||||
|
restore_mepc
|
||||||
|
restore_regs
|
||||||
|
|
||||||
|
/* exit, this will also re-enable the interrupts */
|
||||||
|
mret
|
||||||
|
.size _interrupt_handler, .-_interrupt_handler
|
Reference in New Issue
Block a user