riscv: Add new arch-level component

Changes come from internal branch commit a6723fc
This commit is contained in:
Angus Gratton
2020-11-06 15:03:03 +11:00
parent f5939c9e68
commit fccab8f4ef
13 changed files with 1452 additions and 1 deletions

View 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})

View 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__ */

View 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

View 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

View 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

View 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

View 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

View 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__ */

View 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"
};

View File

@@ -0,0 +1,5 @@
[mapping:riscv]
archive: libriscv.a
entries:
interrupt (noflash_text)
vectors (noflash_text)

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