initial commit
This commit is contained in:
commit
b44ce7bd77
2716 files changed
+559005
No files matched your search
@@ -0,0 +1,300 @@
|
||||
/*
|
||||
* Copyright (c) 2019 Nuclei Limited. All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* 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 __CORE_COMPATIABLE_H__
|
||||
#define __CORE_COMPATIABLE_H__
|
||||
/*!
|
||||
* @file core_compatiable.h
|
||||
* @brief ARM compatiable function definitions header file
|
||||
*/
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "core_feature_base.h"
|
||||
|
||||
/* ===== ARM Compatiable Functions ===== */
|
||||
/**
|
||||
* \defgroup NMSIS_Core_ARMCompatiable_Functions ARM Compatiable Functions
|
||||
* \ingroup NMSIS_Core
|
||||
* \brief A few functions that compatiable with ARM CMSIS-Core.
|
||||
* \details
|
||||
*
|
||||
* Here we provided a few functions that compatiable with ARM CMSIS-Core,
|
||||
* mostly used in the DSP and NN library.
|
||||
* @{
|
||||
*/
|
||||
/** \brief Instruction Synchronization Barrier, compatiable with ARM */
|
||||
#define __ISB() __RWMB()
|
||||
|
||||
/** \brief Data Synchronization Barrier, compatiable with ARM */
|
||||
#define __DSB() __RWMB()
|
||||
|
||||
/** \brief Data Memory Barrier, compatiable with ARM */
|
||||
#define __DMB() __RWMB()
|
||||
|
||||
/** \brief LDRT Unprivileged (8 bit), ARM Compatiable */
|
||||
#define __LDRBT(ptr) __LB((ptr))
|
||||
/** \brief LDRT Unprivileged (16 bit), ARM Compatiable */
|
||||
#define __LDRHT(ptr) __LH((ptr))
|
||||
/** \brief LDRT Unprivileged (32 bit), ARM Compatiable */
|
||||
#define __LDRT(ptr) __LW((ptr))
|
||||
|
||||
/** \brief STRT Unprivileged (8 bit), ARM Compatiable */
|
||||
#define __STRBT(val, ptr) __SB((ptr), (val))
|
||||
/** \brief STRT Unprivileged (16 bit), ARM Compatiable */
|
||||
#define __STRHT(val, ptr) __SH((ptr), (val))
|
||||
/** \brief STRT Unprivileged (32 bit), ARM Compatiable */
|
||||
#define __STRT(val, ptr) __SW((ptr), (val))
|
||||
|
||||
/* ===== Saturation Operations ===== */
|
||||
/**
|
||||
* \brief Signed Saturate
|
||||
* \details Saturates a signed value.
|
||||
* \param [in] value Value to be saturated
|
||||
* \param [in] sat Bit position to saturate to (1..32)
|
||||
* \return Saturated value
|
||||
*/
|
||||
#if defined(__DSP_PRESENT) && (__DSP_PRESENT == 1)
|
||||
#define __SSAT(val, sat) __RV_SCLIP32((val), (sat-1))
|
||||
#else
|
||||
__STATIC_INLINE int32_t __SSAT(int32_t val, uint32_t sat)
|
||||
{
|
||||
if ((sat >= 1U) && (sat <= 32U)) {
|
||||
const int32_t max = (int32_t)((1U << (sat - 1U)) - 1U);
|
||||
const int32_t min = -1 - max ;
|
||||
if (val > max) {
|
||||
return max;
|
||||
} else if (val < min) {
|
||||
return min;
|
||||
}
|
||||
}
|
||||
return val;
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* \brief Unsigned Saturate
|
||||
* \details Saturates an unsigned value.
|
||||
* \param [in] value Value to be saturated
|
||||
* \param [in] sat Bit position to saturate to (0..31)
|
||||
* \return Saturated value
|
||||
*/
|
||||
#if defined(__DSP_PRESENT) && (__DSP_PRESENT == 1)
|
||||
#define __USAT(val, sat) __RV_UCLIP32((val), (sat))
|
||||
#else
|
||||
__STATIC_INLINE uint32_t __USAT(int32_t val, uint32_t sat)
|
||||
{
|
||||
if (sat <= 31U) {
|
||||
const uint32_t max = ((1U << sat) - 1U);
|
||||
if (val > (int32_t)max) {
|
||||
return max;
|
||||
} else if (val < 0) {
|
||||
return 0U;
|
||||
}
|
||||
}
|
||||
return (uint32_t)val;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* ===== Data Processing Operations ===== */
|
||||
/**
|
||||
* \brief Reverse byte order (32 bit)
|
||||
* \details Reverses the byte order in unsigned integer value.
|
||||
* For example, 0x12345678 becomes 0x78563412.
|
||||
* \param [in] value Value to reverse
|
||||
* \return Reversed value
|
||||
*/
|
||||
__STATIC_FORCEINLINE uint32_t __REV(uint32_t value)
|
||||
{
|
||||
uint32_t result;
|
||||
|
||||
result = ((value & 0xff000000) >> 24)
|
||||
| ((value & 0x00ff0000) >> 8 )
|
||||
| ((value & 0x0000ff00) << 8 )
|
||||
| ((value & 0x000000ff) << 24);
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Reverse byte order (16 bit)
|
||||
* \details Reverses the byte order within each halfword of a word.
|
||||
* For example, 0x12345678 becomes 0x34127856.
|
||||
* \param [in] value Value to reverse
|
||||
* \return Reversed value
|
||||
*/
|
||||
__STATIC_FORCEINLINE uint32_t __REV16(uint32_t value)
|
||||
{
|
||||
uint32_t result;
|
||||
result = ((value & 0xff000000) >> 8)
|
||||
| ((value & 0x00ff0000) << 8 )
|
||||
| ((value & 0x0000ff00) >> 8 )
|
||||
| ((value & 0x000000ff) << 8) ;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Reverse byte order (16 bit)
|
||||
* \details Reverses the byte order in a 16-bit value
|
||||
* and returns the signed 16-bit result.
|
||||
* For example, 0x0080 becomes 0x8000.
|
||||
* \param [in] value Value to reverse
|
||||
* \return Reversed value
|
||||
*/
|
||||
__STATIC_FORCEINLINE int16_t __REVSH(int16_t value)
|
||||
{
|
||||
int16_t result;
|
||||
result = ((value & 0xff00) >> 8) | ((value & 0x00ff) << 8);
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Rotate Right in unsigned value (32 bit)
|
||||
* \details Rotate Right (immediate) provides the value of
|
||||
* the contents of a register rotated by a variable number of bits.
|
||||
* \param [in] op1 Value to rotate
|
||||
* \param [in] op2 Number of Bits to rotate(0-31)
|
||||
* \return Rotated value
|
||||
*/
|
||||
__STATIC_FORCEINLINE uint32_t __ROR(uint32_t op1, uint32_t op2)
|
||||
{
|
||||
op2 = op2 & 0x1F;
|
||||
if (op2 == 0U) {
|
||||
return op1;
|
||||
}
|
||||
return (op1 >> op2) | (op1 << (32U - op2));
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Rotate Right in uint32x2 value (64 bit)
|
||||
* \details Rotate Right (immediate) provides the value of
|
||||
* the contents of a register rotated by a variable number of bits.
|
||||
* \param [in] op1 Value to rotate([63:32] and [31:0] rotate separately)
|
||||
* \param [in] op2 Number of Bits to rotate
|
||||
* \return Rotated value([63:32] | [31:0])
|
||||
*/
|
||||
__STATIC_INLINE uint64_t __ROR64(uint64_t op1, uint32_t op2)
|
||||
{
|
||||
op2 = op2 & 0x1F;
|
||||
if (op2 == 0U) {
|
||||
return op1;
|
||||
}
|
||||
uint32_t tmp1 = (uint32_t)op1;
|
||||
uint32_t tmp2 = (uint32_t)(op1 >> 32);
|
||||
return (uint64_t)((tmp1 >> op2) | (tmp1 << (32U - op2)))
|
||||
| ((uint64_t)((tmp2 >> op2) | (tmp2 << (32U - op2))) << 32);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Reverse bit order of value
|
||||
* \details Reverses the bit order of the given value.
|
||||
* \param [in] value Value to reverse
|
||||
* \return Reversed value
|
||||
*/
|
||||
#if defined(__DSP_PRESENT) && (__DSP_PRESENT == 1)
|
||||
#define __RBIT(value) __RV_BITREVI((value), 31)
|
||||
#else
|
||||
__STATIC_INLINE uint32_t __RBIT(uint32_t value)
|
||||
{
|
||||
uint32_t result;
|
||||
uint32_t s = (4U /*sizeof(v)*/ * 8U) - 1U; /* extra shift needed at end */
|
||||
|
||||
result = value; /* r will be reversed bits of v; first get LSB of v */
|
||||
for (value >>= 1U; value != 0U; value >>= 1U) {
|
||||
result <<= 1U;
|
||||
result |= value & 1U;
|
||||
s--;
|
||||
}
|
||||
result <<= s; /* shift when v's highest bits are zero */
|
||||
return result;
|
||||
}
|
||||
#endif /* defined(__DSP_PRESENT) && (__DSP_PRESENT == 1) */
|
||||
|
||||
/**
|
||||
* \brief Count leading zeros
|
||||
* \details Counts the number of leading zeros of a data value.
|
||||
* \param [in] data Value to count the leading zeros
|
||||
* \return number of leading zeros in value
|
||||
*/
|
||||
#if defined(__DSP_PRESENT) && (__DSP_PRESENT == 1)
|
||||
#define __CLZ(data) __RV_CLZ32(data)
|
||||
#else
|
||||
__STATIC_INLINE uint8_t __CLZ(uint32_t data)
|
||||
{
|
||||
uint8_t ret = 0;
|
||||
uint32_t temp = ~data;
|
||||
while (temp & 0x80000000) {
|
||||
temp <<= 1;
|
||||
ret++;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
#endif /* defined(__DSP_PRESENT) && (__DSP_PRESENT == 1) */
|
||||
|
||||
/**
|
||||
* \brief Count tailing zero
|
||||
* \details Return the count of least-significant bit zero.for example, return 3 if x=0bxxx1000
|
||||
* \param [in] data Value to count the tailing zeros
|
||||
* \return number of tailing zeros in value
|
||||
* \remark
|
||||
* - The value mustn't be 0, or else it will spin here
|
||||
*/
|
||||
__STATIC_INLINE unsigned long __CTZ(unsigned long data)
|
||||
{
|
||||
unsigned long ret = 0;
|
||||
|
||||
if (data == 0) {
|
||||
return __RISCV_XLEN;
|
||||
}
|
||||
|
||||
while (!(data & 1UL)) {
|
||||
ret++;
|
||||
data = data >> 1;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Expand byte to unsigned long value
|
||||
* \details Expand byte value x to unsigned long value's each byte.
|
||||
* \param [in] x the byte value to be expand, the input must be uint8_t type
|
||||
* \return Expanded value in unsigned long
|
||||
*/
|
||||
#if __RISCV_XLEN == 32
|
||||
#define __EXPD_BYTE(x) ((unsigned long)(((unsigned long)(x) << 0) | \
|
||||
((unsigned long)(x) << 8) | \
|
||||
((unsigned long)(x) << 16) | \
|
||||
((unsigned long)(x) << 24)))
|
||||
#elif __RISCV_XLEN == 64
|
||||
#define __EXPD_BYTE(x) ((unsigned long)(((unsigned long)(x) << 0) | \
|
||||
((unsigned long)(x) << 8) | \
|
||||
((unsigned long)(x) << 16) | \
|
||||
((unsigned long)(x) << 24) | \
|
||||
((unsigned long)(x) << 32) | \
|
||||
((unsigned long)(x) << 40) | \
|
||||
((unsigned long)(x) << 48) | \
|
||||
((unsigned long)(x) << 56)))
|
||||
#endif
|
||||
|
||||
/** @} */ /* End of Doxygen Group NMSIS_Core_ARMCompatiable_Functions */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif /* __CORE_COMPATIABLE_H__ */
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
* Copyright (c) 2019 Nuclei Limited. All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* 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 __CORE_FEATURE_BITMANIP__
|
||||
#define __CORE_FEATURE_BITMANIP__
|
||||
|
||||
/*!
|
||||
* @file core_feature_bitmanip.h
|
||||
* @brief Bitmanipulation feature API header file for Nuclei N/NX Core
|
||||
*/
|
||||
/*
|
||||
* Bitmanipulation Feature Configuration Macro:
|
||||
* 1. __BITMANIP_PRESENT: Define whether Bitmanipulation Unit is present or not
|
||||
* * 0: Not present
|
||||
* * 1: Present
|
||||
*/
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "core_feature_base.h"
|
||||
|
||||
#if defined(__BITMANIP_PRESENT) && (__BITMANIP_PRESENT == 1)
|
||||
|
||||
/* ########################### CPU Bitmanipulation Intrinsic Functions ########################### */
|
||||
/**
|
||||
* \defgroup NMSIS_Core_Bitmanip_Intrinsic Intrinsic Functions for Bitmanipulation Instructions
|
||||
* \ingroup NMSIS_Core
|
||||
* \brief Functions that generate RISC-V Bitmanipulation instructions.
|
||||
* \details
|
||||
*
|
||||
* RISC-V Bitmanipulation Intrinsic APIs are provided directly through compiler generated intrinsic function.
|
||||
*
|
||||
* This intrinsic function support in compiler is introduced in nuclei riscv gcc 10.2.
|
||||
*
|
||||
* API header file can be found in lib/gcc/riscv-nuclei-elf/<gcc_ver>/include/rvintrin.h
|
||||
*
|
||||
* For Nuclei GCC 13/Clang 17 and later version, this intrinsic header no longer existed, please take care.
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
/** @} */ /* End of Doxygen Group NMSIS_Core_Bitmanip_Intrinsic */
|
||||
|
||||
#if defined(__INC_INTRINSIC_API) && (__INC_INTRINSIC_API == 1)
|
||||
// deleted in gcc13, you can directly use b extension intrinisc api
|
||||
//#include <rvintrin.h>
|
||||
#endif
|
||||
|
||||
#endif /* defined(__BITMANIP_PRESENT) && (__BITMANIP_PRESENT == 1) */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __CORE_FEATURE_BITMANIP__ */
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,442 @@
|
||||
/*
|
||||
* Copyright (c) 2019 Nuclei Limited. All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* 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 __CORE_FEATURE_CIDU_H__
|
||||
#define __CORE_FEATURE_CIDU_H__
|
||||
/*!
|
||||
* @file core_feature_cidu.h
|
||||
* @brief Cluster Interrupt Distribution Unit feature API header file for Nuclei N/NX Core
|
||||
*/
|
||||
/*
|
||||
* CIDU Feature Configuration Macro:
|
||||
* 1. __CIDU_PRESENT: Define whether Cluster Interrupt Distribution Unit is present or not.
|
||||
* * 0: Not present
|
||||
* * 1: Present
|
||||
* 2. __CIDU_BASEADDR: Define the base address of the CIDU.
|
||||
*/
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "core_feature_base.h"
|
||||
|
||||
#if defined(__CIDU_PRESENT) && (__CIDU_PRESENT == 1)
|
||||
|
||||
/* ########################## CIDU functions #################################### */
|
||||
/**
|
||||
* \defgroup NMSIS_Core_CIDU CIDU Functions
|
||||
* \ingroup NMSIS_Core
|
||||
* \brief Functions that manage external interrupts, inter core interrupts and semaphores.
|
||||
* \details
|
||||
*
|
||||
* Nuclei provide Cluster Interrupt Distribution Unit (CIDU) for scenarios that a SMP system is designed for real
|
||||
* time application or both Linux and real time application, and Nuclei processor core can optionally support CIDU.
|
||||
* The CIDU is used to distribute external interrupts to the core’s ECLIC, also it provides Inter Core Interrupt (ICI)
|
||||
* and Semaphores Mechanism. Its features are as follows:
|
||||
*
|
||||
* * Support up to 16 Cores in one cluster
|
||||
* * Support up to 4096 external interrupts sources
|
||||
* * Support up to 16 Inter Core Interrupts
|
||||
* * Support 32 Semaphores
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
|
||||
#ifndef __CIDU_BASEADDR
|
||||
/* Base address of CIDU(__CIDU_BASEADDR) should be defined in <Device.h> */
|
||||
#error "__CIDU_BASEADDR is not defined, please check!"
|
||||
#endif
|
||||
|
||||
#define CIDU_BASE __CIDU_BASEADDR
|
||||
#define CIDU_RECEIVE_INTERRUPT_EN(core_id) (0x1UL << core_id) /*!< Indicates the core can receive corresponding interrupt */
|
||||
|
||||
#define CIDU_CORE_INT_STATUS_OFS 0x0 /*!< Core n Inter Core Interrupt status register base offset */
|
||||
#define CIDU_SEMAPHORE_OFS 0x80 /*!< Semaphore n register base offset */
|
||||
#define CIDU_ICI_SHADOW_OFS 0x3FFC /*!< ICI Interrupt source core ID and target core ID register offset */
|
||||
#define CIDU_INT_INDICATOR_OFS 0x4000 /*!< External interrupt n indicator register base offset */
|
||||
#define CIDU_INT_MASK_OFS 0x8000 /*!< External interrupt n mask (mask interrupt n to cores or not when interrupt n indicator on)register base offset */
|
||||
#define CIDU_CORE_NUM_OFS 0xC084 /*!< Static configuration core num register offset */
|
||||
#define CIDU_INT_NUM_OFS 0xC090 /*!< Static configuration external interrupt number register offset */
|
||||
|
||||
#define CIDU_CORE_INT_STATUS_ADDR(n) (unsigned long)((CIDU_BASE) + (CIDU_CORE_INT_STATUS_OFS) + ((n) << 2)) /*!< Core n Inter Core Interrupt status register address */
|
||||
#define CIDU_SEMAPHORE_ADDR(n) (unsigned long)((CIDU_BASE) + (CIDU_SEMAPHORE_OFS) + ((n) << 2)) /*!< Semaphore n register address */
|
||||
#define CIDU_ICI_SHADOW_ADDR (unsigned long)((CIDU_BASE) + (CIDU_ICI_SHADOW_OFS)) /*!< ICI Interrupt source core ID and target core ID register address */
|
||||
#define CIDU_INT_INDICATOR_ADDR(n) (unsigned long)((CIDU_BASE) + (CIDU_INT_INDICATOR_OFS) + ((n) << 2)) /*!< External interrupt n indicator register address */
|
||||
#define CIDU_INT_MASK_ADDR(n) (unsigned long)((CIDU_BASE) + (CIDU_INT_MASK_OFS) + ((n) << 2)) /*!< External interrupt n mask (mask interrupt n to cores or not when interrupt n indicator on)register address */
|
||||
#define CIDU_CORE_NUM_ADDR (unsigned long)((CIDU_BASE) + (CIDU_CORE_NUM_OFS)) /*!< Static configuration core num register address */
|
||||
#define CIDU_INT_NUM_ADDR (unsigned long)((CIDU_BASE) + (CIDU_INT_NUM_OFS)) /*!< Static configuration external interrupt number register address */
|
||||
|
||||
|
||||
/* SEND_CORE_ID position in ICI_SHADOW_REG register */
|
||||
#define CIDU_ICI_SEND_CORE_ID_POS 16
|
||||
|
||||
/**
|
||||
* \brief Get core number in the cluster
|
||||
* \details
|
||||
* Indicate the static configuration core num in the cluster.
|
||||
* \return core number configured
|
||||
* \remarks
|
||||
* - In a Nulcei multi-core system, each core has an identifiable serial number, the serial number starts from 0 and is
|
||||
* continuous, also the number is static.
|
||||
* - CORE_NUM register is read only.
|
||||
*/
|
||||
__STATIC_FORCEINLINE uint32_t CIDU_GetCoreNum(void)
|
||||
{
|
||||
uint32_t val;
|
||||
uint32_t* addr = (uint32_t*)CIDU_CORE_NUM_ADDR;
|
||||
|
||||
val = __LW(addr);
|
||||
return val;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Get external interrupt number
|
||||
* \details
|
||||
* Indicate the static configuration external interrupt number
|
||||
* \return interrupt number configured
|
||||
* \remarks
|
||||
* - INT_NUM register is read only.
|
||||
*/
|
||||
__STATIC_FORCEINLINE uint32_t CIDU_GetIntNum(void)
|
||||
{
|
||||
uint32_t val;
|
||||
uint32_t* addr = (uint32_t*)CIDU_INT_NUM_ADDR;
|
||||
|
||||
val = __LW(addr);
|
||||
return val;
|
||||
}
|
||||
/** @} */ /* End of Doxygen Group NMSIS_Core_CIDU */
|
||||
|
||||
/**
|
||||
* \defgroup NMSIS_Core_Distribute_Interrupt External Interrupt Distribution Functions
|
||||
* \ingroup NMSIS_Core_CIDU
|
||||
* \brief Functions that distribute external interrupts to cores.
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* \brief Broadcast external interrupt to cores
|
||||
* \details
|
||||
* This function broadcasts external interrupt which id is int_id to some/all target cores
|
||||
* \param [in] int_id external interrupt id
|
||||
* \param [in] to_cores target cores which can receive interrupt, use bitwise inclusive or
|
||||
* of \ref CIDU_RECEIVE_INTERRUPT_EN(core_id)
|
||||
* \remarks
|
||||
* - External IRQn ID(int_id) is from the hard-wired persperctive,
|
||||
* which has an offset mapped to the ECLIC IRQn, see Interrupt Number Definition in <Device.h>
|
||||
* - By default on reset, only core 0 can receive interrupt which id is int_id
|
||||
*/
|
||||
__STATIC_FORCEINLINE void CIDU_BroadcastExtInterrupt(uint32_t int_id, uint32_t to_cores)
|
||||
{
|
||||
uint32_t* addr = (uint32_t*)CIDU_INT_INDICATOR_ADDR(int_id);
|
||||
|
||||
__SW(addr, (uint32_t)to_cores);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief get broadcast mode status
|
||||
* \details
|
||||
* Just query the INTn_INDICATOR register value
|
||||
* \param [in] int_id external interrupt id
|
||||
* \return INTn_INDICATOR register value
|
||||
* \remarks
|
||||
* - External IRQn ID(int_id) is from the hard-wired persperctive,
|
||||
* which has an offset mapped to the ECLIC IRQn, see Interrupt Number Definition in <Device.h>
|
||||
* - By default on reset, only core 0 can receive interrupt which id is int_id
|
||||
*/
|
||||
__STATIC_FORCEINLINE uint32_t CIDU_GetBroadcastModeStatus(uint32_t int_id)
|
||||
{
|
||||
uint32_t val = 0;
|
||||
uint32_t* addr = (uint32_t*)CIDU_INT_INDICATOR_ADDR(int_id);
|
||||
|
||||
val = __LW(addr);
|
||||
return val;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Let the first coming core to first claim the interrupt
|
||||
* \details
|
||||
* In external interrupt broadcast mode, make the first coming core to claim this interrupt and then can handle it.
|
||||
* \param [in] int_id external interrupt id
|
||||
* \param [in] core_id core id that receive the interrupt
|
||||
* \return -1 if it fails to claim the interrupt, else it can continue to handle the interrupt
|
||||
* \remarks
|
||||
* - External IRQn ID(int_id) is from the hard-wired persperctive,
|
||||
* which has an offset mapped to the ECLIC IRQn, see Interrupt Number Definition in <Device.h>.
|
||||
* - If it fails to claim the interrupt, it should quit the interrupt n's handler of all cores
|
||||
* - When a core claims the interrupt successfully and has handled it, it must call \ref CIDU_ResetFirstClaimMode to reset the claim.
|
||||
* \sa
|
||||
* - \ref CIDU_BroadcastExtInterrupt
|
||||
* - \ref CIDU_ResetFirstClaimMode
|
||||
*/
|
||||
__STATIC_INLINE long CIDU_SetFirstClaimMode(uint32_t int_id, uint32_t core_id)
|
||||
{
|
||||
uint32_t val = 0;
|
||||
uint32_t* addr = (uint32_t*)CIDU_INT_MASK_ADDR(int_id);
|
||||
uint32_t mask = 1UL << core_id;
|
||||
|
||||
__SW(addr, mask);
|
||||
val = __LW(addr);
|
||||
if (mask == val) {
|
||||
return 0;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Reset the claim mode mask
|
||||
* \details
|
||||
* Reset the claim mode mask by Writing the reset value (all 1) to it
|
||||
* \param [in] int_id external interrupt id
|
||||
* \remarks
|
||||
* - External IRQn ID(int_id) is from the hard-wired persperctive,
|
||||
* which has an offset mapped to the ECLIC IRQn, see Interrupt Number Definition in <Device.h>
|
||||
* - When a core claims the interrupt successfully and handle it, it must call \ref CIDU_ResetFirstClaimMode to reset the claim
|
||||
* \sa
|
||||
* - \ref CIDU_SetFirstClaimMode
|
||||
*/
|
||||
__STATIC_FORCEINLINE void CIDU_ResetFirstClaimMode(uint32_t int_id)
|
||||
{
|
||||
uint32_t val = 0;
|
||||
uint32_t* addr = (uint32_t*)CIDU_INT_MASK_ADDR(int_id);
|
||||
|
||||
/* clear by writing all 1 */
|
||||
__SW(addr, 0xFFFFFFFF);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Get the claim mask status
|
||||
* \details
|
||||
* Get the claim mode staus, each bit[n] indicates whether core n has claimed interrupt successfully,
|
||||
* 1 means yes, 0 means no.
|
||||
* \param [in] int_id external interrupt id
|
||||
* \return claim mode register INTn_MASK value
|
||||
* \remarks
|
||||
* - External IRQn ID(int_id) is from the hard-wired persperctive,
|
||||
* which has an offset mapped to the ECLIC IRQn, see Interrupt Number Definition in <Device.h>
|
||||
* \sa
|
||||
* - \ref CIDU_ResetFirstClaimMode
|
||||
* - \ref CIDU_SetFirstClaimMode
|
||||
*/
|
||||
__STATIC_FORCEINLINE uint32_t CIDU_GetClaimStatus(uint32_t int_id)
|
||||
{
|
||||
uint32_t val = 0;
|
||||
uint32_t* addr = (uint32_t*)CIDU_INT_MASK_ADDR(int_id);
|
||||
|
||||
val = __LW(addr);
|
||||
return val;
|
||||
}
|
||||
/** @} */ /* End of Doxygen Group NMSIS_Core_Distribute_Interrupt */
|
||||
|
||||
/**
|
||||
* \defgroup NMSIS_Core_ICI Inter Core Interrupt Functions
|
||||
* \ingroup NMSIS_Core_CIDU
|
||||
* \brief Functions that implement Inter Core Interrupt mechanism.
|
||||
* @{
|
||||
* Inter Core Interrupt (ICI) means that one core can send interrupt to another core in a multi-core cluster. CIDU ICI belongs
|
||||
* to Internal Interrupt.
|
||||
*
|
||||
* * CIDU ICI Interrupt ID is fixed to 16.
|
||||
*/
|
||||
|
||||
/**
|
||||
* \brief Trigger interrupt to another core in a multi-core cluster
|
||||
* \details
|
||||
* When called by core send_core_id, CIDU will trigger ICI to core recv_core_id automatically.
|
||||
* and core recv_core_id could query \ref CIDU_GetCoreIntSenderId to know the sender.
|
||||
* \param [in] send_core_id the core id which want to send the inter core interrupt
|
||||
* \param [in] recv_core_id the core id which will receive the inter core interrupt
|
||||
* \remarks
|
||||
* - The core recv_core_id need to call CIDU_ClearInterCoreIntReq to clear the corresponding bit/bits
|
||||
* of its own COREn_INT_STATUS.
|
||||
* - It supports that multiple cores call \ref CIDU_TriggerInterCoreInt simultaneously.
|
||||
* \sa
|
||||
* - \ref CIDU_GetCoreIntSenderId
|
||||
* - \ref CIDU_ClearInterCoreIntReq
|
||||
*/
|
||||
__STATIC_FORCEINLINE void CIDU_TriggerInterCoreInt(uint32_t send_core_id, uint32_t recv_core_id)
|
||||
{
|
||||
uint32_t val = 0;
|
||||
uint32_t* addr = (uint32_t*)CIDU_ICI_SHADOW_ADDR;
|
||||
|
||||
val = (uint32_t)(send_core_id << CIDU_ICI_SEND_CORE_ID_POS) | (uint32_t)(recv_core_id);
|
||||
__SW(addr, (uint32_t)val);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Core recv_core_id queries out who sends inter core interrupt to itself
|
||||
* \details
|
||||
* In the ISR of ICI, receive core can query if bit[n] of this return value is 1, core n sends the current ICI,
|
||||
* if bit[m] is 1, then core m also sends, etc.
|
||||
* \param [in] recv_core_id the core id which receives the inter core interrupt
|
||||
* \return Value that shows sender core's ID n whose bit[n](bit[m] if core m send too, etc.) is 1
|
||||
* \remarks
|
||||
* - If the ICI ISR has finished the job, should call \ref CIDU_ClearInterCoreIntReq to clear the IRQ
|
||||
*/
|
||||
__STATIC_FORCEINLINE uint32_t CIDU_QueryCoreIntSenderMask(uint32_t recv_core_id)
|
||||
{
|
||||
uint32_t val = 0;
|
||||
uint32_t* addr = (uint32_t*)CIDU_CORE_INT_STATUS_ADDR(recv_core_id);
|
||||
|
||||
val = __LW(addr);
|
||||
return val;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Clear the corresponding bit/bits of ICI request triggered by sender core
|
||||
* \details
|
||||
* Core recv_core_id write 1 to clear the bit send_core_id of the core recv_core_id's COREn_INT_STATUS.
|
||||
* \param [in] send_core_id the core id which wants to send the inter core interrupt
|
||||
* \param [in] recv_core_id the core id which will receive the inter core interrupt
|
||||
* \remarks
|
||||
* - If the ICI ISR has finished the job of send_core_id_n's ICI, then clear bit send_core_id_n;
|
||||
* if it has finished send_core_id_n and send_core_id_m's, then should clear both the bits, etc.
|
||||
*/
|
||||
__STATIC_FORCEINLINE void CIDU_ClearInterCoreIntReq(uint32_t send_core_id, uint32_t recv_core_id)
|
||||
{
|
||||
uint32_t val = 0;
|
||||
uint32_t* addr = (uint32_t*)CIDU_CORE_INT_STATUS_ADDR(recv_core_id);
|
||||
|
||||
val = (uint32_t)(1UL << send_core_id);
|
||||
__SW(addr, val);
|
||||
}
|
||||
/** @} */ /* End of Doxygen Group NMSIS_Core_ICI */
|
||||
|
||||
/**
|
||||
* \defgroup NMSIS_Core_Semaphore Semaphore Functions
|
||||
* \ingroup NMSIS_Core_CIDU
|
||||
* \brief Functions that configure and use semaphores
|
||||
* @{
|
||||
* Semaphore is very useful for multi-core cluster without SMP enable.
|
||||
*
|
||||
* * All Cores in the cluster agree on using SEMAPHORE_n register to protect a critical resource (an UART device for example).
|
||||
* * If Core n wants to access the critical resource, it should try to own the SEMPAPHORE_n register, or else it can’t access the critical resource.
|
||||
* * When the Core n owns the register SEMPAPHORE_n and finishes the job related the critical resource, then it should
|
||||
* release the register by writing all 1 to it.
|
||||
*/
|
||||
|
||||
/**
|
||||
* \brief Get SEMAPHOREn's value
|
||||
* \details
|
||||
* Just query the semaphore n's value
|
||||
* \param [in] semph_n the semaphore id used to protect a critical resource
|
||||
* \return register SEMAPHOREn_STATUS value
|
||||
*/
|
||||
__STATIC_FORCEINLINE uint32_t CIDU_GetSemaphoreStatus(uint32_t semph_n)
|
||||
{
|
||||
uint32_t val;
|
||||
uint32_t* addr = (uint32_t*)CIDU_SEMAPHORE_ADDR(semph_n);
|
||||
|
||||
val = __LW(addr);
|
||||
return val;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief check SEMAPHOREn's acquired status
|
||||
* \details
|
||||
* Query that whether SEMAPHOREn has been acquired by one core successfully.
|
||||
* \param [in] semph_n the semaphore id used to protect a critical resource
|
||||
* \param [in] core_id the core id that wants to access the critical resource
|
||||
* \return 0 if core_id has acquired this semaphore successfully, or else -1 if failed
|
||||
* \remarks
|
||||
* - When the core n owns the register SEMPAPHORE_n and finishes the job related the critical resource,
|
||||
* it should call \ref CIDU_ReleaseSemaphore to release it.
|
||||
* \sa
|
||||
* - \ref CIDU_GetSemaphoreStatus
|
||||
* - \ref CIDU_ReleaseSemaphore
|
||||
*/
|
||||
__STATIC_INLINE long CIDU_CheckSemaphoreAcquired(uint32_t semph_n, uint32_t core_id)
|
||||
{
|
||||
uint32_t val;
|
||||
val = CIDU_GetSemaphoreStatus(semph_n);
|
||||
if (core_id != val) {
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Acquire the SEMAPHOREn
|
||||
* \details
|
||||
* Acuqire the SEMAPHOREn, and check the acquired status
|
||||
* \param [in] semph_n the semaphore id used to protect a critical resource
|
||||
* \param [in] core_id the core id that wants to access the critical resource
|
||||
* \return 0 if core_id has acquired this semaphore successfully, or else -1 if failed
|
||||
* \remarks
|
||||
* - When the core n owns the register SEMPAPHORE_n and finishes the job related the critical resource,
|
||||
* it should call \ref CIDU_ReleaseSemaphore to release it.
|
||||
* \sa
|
||||
* - \ref CIDU_CheckSemaphoreAcquired
|
||||
* - \ref CIDU_ReleaseSemaphore
|
||||
*/
|
||||
__STATIC_INLINE long CIDU_AcquireSemaphore(uint32_t semph_n, uint32_t core_id)
|
||||
{
|
||||
long semaphore_status = -1;
|
||||
uint32_t* addr = (uint32_t*)CIDU_SEMAPHORE_ADDR(semph_n);
|
||||
|
||||
__SW(addr, core_id);
|
||||
semaphore_status = CIDU_CheckSemaphoreAcquired(semph_n, core_id);
|
||||
return semaphore_status;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Keep acquiring the SEMAPHOREn until it has acquired this semaphore successfully
|
||||
* \details
|
||||
* Query that whether SEMAPHOREn has been owned by one core successfully, if not, keep trying.
|
||||
* \param [in] semph_n the semaphore id used to protect a critical resource
|
||||
* \param [in] core_id the core id that wants to access the critical resource
|
||||
* \remarks
|
||||
* - Core n will block here acquiring, so take care that core should release the semaphore when related job done.
|
||||
* \sa
|
||||
* - \ref CIDU_AcquireSemaphore
|
||||
* - \ref CIDU_ReleaseSemaphore
|
||||
*/
|
||||
__STATIC_INLINE void CIDU_AcquireSemaphore_Block(uint32_t semph_n, uint32_t core_id)
|
||||
{
|
||||
int32_t semaphore_status = -1;
|
||||
|
||||
while(0 != semaphore_status) {
|
||||
semaphore_status = CIDU_AcquireSemaphore(semph_n, core_id);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Release the SEMAPHOREn
|
||||
* \details
|
||||
* Release the SEMAPHOREn by writing all 1 to SEMAPHOREn register.
|
||||
* \param [in] semph_n the semaphore id used to protect a critical resource
|
||||
* \remarks
|
||||
* - When the core finishes the job related to the critical resource, it should release the corresponding semaphore.
|
||||
* \sa
|
||||
* - \ref CIDU_AcquireSemaphore_Block
|
||||
*/
|
||||
__STATIC_FORCEINLINE void CIDU_ReleaseSemaphore(uint32_t semph_n)
|
||||
{
|
||||
uint32_t* addr = (uint32_t*)CIDU_SEMAPHORE_ADDR(semph_n);
|
||||
|
||||
/* Release by writing all 1 */
|
||||
__SW(addr, 0xFFFFFFFF);
|
||||
}
|
||||
/** @} */ /* End of Doxygen Group NMSIS_Core_Semaphore */
|
||||
|
||||
/** @} */ /* End of Doxygen Group NMSIS_Core_CIDU_Functions */
|
||||
#endif /* defined(__CIDU_PRESENT) && (__CIDU_PRESENT == 1) */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif /* __CORE_FEATURE_CIDU_H__ */
|
||||
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,311 @@
|
||||
/*
|
||||
* Copyright (c) 2019 Nuclei Limited. All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* 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 __CORE_FEATURE_FPU_H__
|
||||
#define __CORE_FEATURE_FPU_H__
|
||||
/*!
|
||||
* @file core_feature_fpu.h
|
||||
* @brief FPU feature API header file for Nuclei N/NX Core
|
||||
*/
|
||||
/*
|
||||
* FPU Feature Configuration Macro:
|
||||
* 1. __FPU_PRESENT: Define whether Floating Point Unit(FPU) is present or not
|
||||
* * 0: Not present
|
||||
* * 1: Single precision FPU present, __RISCV_FLEN == 32
|
||||
* * 2: Double precision FPU present, __RISCV_FLEN == 64
|
||||
*/
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "core_feature_base.h"
|
||||
|
||||
/* ===== FPU Operations ===== */
|
||||
/**
|
||||
* \defgroup NMSIS_Core_FPU_Functions FPU Functions
|
||||
* \ingroup NMSIS_Core
|
||||
* \brief Functions that related to the RISC-V FPU (F and D extension).
|
||||
* \details
|
||||
*
|
||||
* Nuclei provided floating point unit by RISC-V F and D extension.
|
||||
* * `F extension` adds single-precision floating-point computational
|
||||
* instructions compliant with the IEEE 754-2008 arithmetic standard, __RISCV_FLEN = 32.
|
||||
* The F extension adds 32 floating-point registers, f0-f31, each 32 bits wide,
|
||||
* and a floating-point control and status register fcsr, which contains the
|
||||
* operating mode and exception status of the floating-point unit.
|
||||
* * `D extension` adds double-precision floating-point computational instructions
|
||||
* compliant with the IEEE 754-2008 arithmetic standard.
|
||||
* The D extension widens the 32 floating-point registers, f0-f31, to 64 bits, __RISCV_FLEN = 64
|
||||
* @{
|
||||
*/
|
||||
#if defined(__FPU_PRESENT) && (__FPU_PRESENT > 0)
|
||||
|
||||
#if __FPU_PRESENT == 1
|
||||
/** \brief Refer to the width of the floating point register in bits(either 32 or 64) */
|
||||
#define __RISCV_FLEN 32
|
||||
#elif __FPU_PRESENT == 2
|
||||
#define __RISCV_FLEN 64
|
||||
#else
|
||||
#define __RISCV_FLEN __riscv_flen
|
||||
#endif /* __FPU_PRESENT == 1 */
|
||||
|
||||
/** \brief Get FCSR CSR Register */
|
||||
#define __get_FCSR() __RV_CSR_READ(CSR_FCSR)
|
||||
/** \brief Set FCSR CSR Register with val */
|
||||
#define __set_FCSR(val) __RV_CSR_WRITE(CSR_FCSR, (val))
|
||||
/** \brief Get FRM CSR Register */
|
||||
#define __get_FRM() __RV_CSR_READ(CSR_FRM)
|
||||
/** \brief Set FRM CSR Register with val */
|
||||
#define __set_FRM(val) __RV_CSR_WRITE(CSR_FRM, (val))
|
||||
/** \brief Get FFLAGS CSR Register */
|
||||
#define __get_FFLAGS() __RV_CSR_READ(CSR_FFLAGS)
|
||||
/** \brief Set FFLAGS CSR Register with val */
|
||||
#define __set_FFLAGS(val) __RV_CSR_WRITE(CSR_FFLAGS, (val))
|
||||
|
||||
/** \brief Enable FPU Unit, and set state to initial */
|
||||
#define __enable_FPU() { __RV_CSR_CLEAR(CSR_MSTATUS, MSTATUS_FS); \
|
||||
__RV_CSR_SET(CSR_MSTATUS, MSTATUS_FS_INITIAL); \
|
||||
}
|
||||
/**
|
||||
* \brief Disable FPU Unit
|
||||
* \details
|
||||
* * We can save power by disable FPU Unit.
|
||||
* * When FPU Unit is disabled, any access to FPU related CSR registers
|
||||
* and FPU instructions will cause illegal Instuction Exception.
|
||||
* */
|
||||
#define __disable_FPU() __RV_CSR_CLEAR(CSR_MSTATUS, MSTATUS_FS)
|
||||
|
||||
|
||||
/**
|
||||
* \brief Load a single-precision value from memory into float point register freg using flw instruction
|
||||
* \details The FLW instruction loads a single-precision floating point value from memory
|
||||
* address (addr + ofs) into floating point register freg(f0-f31)
|
||||
* \param [in] freg The floating point register, eg. FREG(0), f0
|
||||
* \param [in] addr The memory base address, 4 byte aligned required
|
||||
* \param [in] ofs a 12-bit immediate signed byte offset value, should be an const value
|
||||
* \remarks
|
||||
* * FLW and FSW operations need to make sure the address is 4 bytes aligned,
|
||||
* otherwise it will cause exception code 4(Load address misaligned) or 6 (Store/AMO address misaligned)
|
||||
* * FLW and FSW do not modify the bits being transferred; in particular, the payloads of non-canonical
|
||||
* NaNs are preserved
|
||||
*
|
||||
*/
|
||||
#define __RV_FLW(freg, addr, ofs) \
|
||||
({ \
|
||||
rv_csr_t __addr = (rv_csr_t)(addr); \
|
||||
__ASM volatile("flw " STRINGIFY(freg) ", %0(%1) " \
|
||||
: : "I"(ofs), "r"(__addr) \
|
||||
: "memory"); \
|
||||
})
|
||||
|
||||
/**
|
||||
* \brief Store a single-precision value from float point freg into memory using fsw instruction
|
||||
* \details The FSW instruction stores a single-precision value from floating point register to memory
|
||||
* \param [in] freg The floating point register(f0-f31), eg. FREG(0), f0
|
||||
* \param [in] addr The memory base address, 4 byte aligned required
|
||||
* \param [in] ofs a 12-bit immediate signed byte offset value, should be an const value
|
||||
* \remarks
|
||||
* * FLW and FSW operations need to make sure the address is 4 bytes aligned,
|
||||
* otherwise it will cause exception code 4(Load address misaligned) or 6 (Store/AMO address misaligned)
|
||||
* * FLW and FSW do not modify the bits being transferred; in particular, the payloads of non-canonical
|
||||
* NaNs are preserved
|
||||
*
|
||||
*/
|
||||
#define __RV_FSW(freg, addr, ofs) \
|
||||
({ \
|
||||
rv_csr_t __addr = (rv_csr_t)(addr); \
|
||||
__ASM volatile("fsw " STRINGIFY(freg) ", %0(%1) " \
|
||||
: : "I"(ofs), "r"(__addr) \
|
||||
: "memory"); \
|
||||
})
|
||||
|
||||
/**
|
||||
* \brief Load a double-precision value from memory into float point register freg using fld instruction
|
||||
* \details The FLD instruction loads a double-precision floating point value from memory
|
||||
* address (addr + ofs) into floating point register freg(f0-f31)
|
||||
* \param [in] freg The floating point register, eg. FREG(0), f0
|
||||
* \param [in] addr The memory base address, 8 byte aligned required
|
||||
* \param [in] ofs a 12-bit immediate signed byte offset value, should be an const value
|
||||
* \attention
|
||||
* * Function only available for double precision floating point unit, FLEN = 64
|
||||
* \remarks
|
||||
* * FLD and FSD operations need to make sure the address is 8 bytes aligned,
|
||||
* otherwise it will cause exception code 4(Load address misaligned) or 6 (Store/AMO address misaligned)
|
||||
* * FLD and FSD do not modify the bits being transferred; in particular, the payloads of non-canonical
|
||||
* NaNs are preserved.
|
||||
*/
|
||||
#define __RV_FLD(freg, addr, ofs) \
|
||||
({ \
|
||||
rv_csr_t __addr = (rv_csr_t)(addr); \
|
||||
__ASM volatile("fld " STRINGIFY(freg) ", %0(%1) " \
|
||||
: : "I"(ofs), "r"(__addr) \
|
||||
: "memory"); \
|
||||
})
|
||||
|
||||
/**
|
||||
* \brief Store a double-precision value from float point freg into memory using fsd instruction
|
||||
* \details The FSD instruction stores double-precision value from floating point register to memory
|
||||
* \param [in] freg The floating point register(f0-f31), eg. FREG(0), f0
|
||||
* \param [in] addr The memory base address, 8 byte aligned required
|
||||
* \param [in] ofs a 12-bit immediate signed byte offset value, should be an const value
|
||||
* \attention
|
||||
* * Function only available for double precision floating point unit, FLEN = 64
|
||||
* \remarks
|
||||
* * FLD and FSD operations need to make sure the address is 8 bytes aligned,
|
||||
* otherwise it will cause exception code 4(Load address misaligned) or 6 (Store/AMO address misaligned)
|
||||
* * FLD and FSD do not modify the bits being transferred; in particular, the payloads of non-canonical
|
||||
* NaNs are preserved.
|
||||
*
|
||||
*/
|
||||
#define __RV_FSD(freg, addr, ofs) \
|
||||
({ \
|
||||
rv_csr_t __addr = (rv_csr_t)(addr); \
|
||||
__ASM volatile("fsd " STRINGIFY(freg) ", %0(%1) " \
|
||||
: : "I"(ofs), "r"(__addr) \
|
||||
: "memory"); \
|
||||
})
|
||||
|
||||
/**
|
||||
* \def __RV_FLOAD
|
||||
* \brief Load a float point value from memory into float point register freg using flw/fld instruction
|
||||
* \details
|
||||
* * For Single-Precison Floating-Point Mode(__FPU_PRESENT == 1, __RISCV_FLEN == 32):
|
||||
* It will call \ref __RV_FLW to load a single-precision floating point value from memory to floating point register
|
||||
* * For Double-Precison Floating-Point Mode(__FPU_PRESENT == 2, __RISCV_FLEN == 64):
|
||||
* It will call \ref __RV_FLD to load a double-precision floating point value from memory to floating point register
|
||||
*
|
||||
* \attention
|
||||
* Function behaviour is different for __FPU_PRESENT = 1 or 2, please see the real function this macro represent
|
||||
*/
|
||||
/**
|
||||
* \def __RV_FSTORE
|
||||
* \brief Store a float value from float point freg into memory using fsw/fsd instruction
|
||||
* \details
|
||||
* * For Single-Precison Floating-Point Mode(__FPU_PRESENT == 1, __RISCV_FLEN == 32):
|
||||
* It will call \ref __RV_FSW to store floating point register into memory
|
||||
* * For Double-Precison Floating-Point Mode(__FPU_PRESENT == 2, __RISCV_FLEN == 64):
|
||||
* It will call \ref __RV_FSD to store floating point register into memory
|
||||
*
|
||||
* \attention
|
||||
* Function behaviour is different for __FPU_PRESENT = 1 or 2, please see the real function this macro represent
|
||||
*/
|
||||
#if __FPU_PRESENT == 1
|
||||
#define __RV_FLOAD __RV_FLW
|
||||
#define __RV_FSTORE __RV_FSW
|
||||
/** \brief Type of FPU register, depends on the FLEN defined in RISC-V */
|
||||
typedef uint32_t rv_fpu_t;
|
||||
#elif __FPU_PRESENT == 2
|
||||
#define __RV_FLOAD __RV_FLD
|
||||
#define __RV_FSTORE __RV_FSD
|
||||
/** \brief Type of FPU register, depends on the FLEN defined in RISC-V */
|
||||
typedef uint64_t rv_fpu_t;
|
||||
#endif /* __FPU_PRESENT == 2 */
|
||||
|
||||
/**
|
||||
* \brief Save FPU context into variables for interrupt nesting
|
||||
* \details
|
||||
* This macro is used to declare variables which are used for saving
|
||||
* FPU context + FCSR, and it will store the nessary fpu registers into
|
||||
* these variables, it need to be used in a interrupt when in this
|
||||
* interrupt fpu registers are used.
|
||||
* \remarks
|
||||
* - It need to be used together with \ref RESTORE_FPU_CONTEXT
|
||||
* - Don't use variable names __fpu_context in your ISR code
|
||||
* - If you isr code will use fpu registers, and this interrupt is nested.
|
||||
* Then you can do it like this:
|
||||
* \code
|
||||
* void eclic_mtip_handler(void)
|
||||
* {
|
||||
* // !!!Interrupt is enabled here!!!
|
||||
* // !!!Higher priority interrupt could nest it!!!
|
||||
*
|
||||
* // Necessary only when you need to use fpu registers
|
||||
* // in this isr handler functions
|
||||
* SAVE_FPU_CONTEXT();
|
||||
*
|
||||
* // put you own interrupt handling code here
|
||||
*
|
||||
* // pair of SAVE_FPU_CONTEXT()
|
||||
* RESTORE_FPU_CONTEXT();
|
||||
* }
|
||||
* \endcode
|
||||
*/
|
||||
#define SAVE_FPU_CONTEXT() \
|
||||
rv_fpu_t __fpu_context[20]; \
|
||||
rv_csr_t __fcsr; \
|
||||
__fcsr = __get_FCSR(); \
|
||||
__RV_FSTORE(FREG(0), __fpu_context, 0 << LOG_FPREGBYTES); \
|
||||
__RV_FSTORE(FREG(1), __fpu_context, 1 << LOG_FPREGBYTES); \
|
||||
__RV_FSTORE(FREG(2), __fpu_context, 2 << LOG_FPREGBYTES); \
|
||||
__RV_FSTORE(FREG(3), __fpu_context, 3 << LOG_FPREGBYTES); \
|
||||
__RV_FSTORE(FREG(4), __fpu_context, 4 << LOG_FPREGBYTES); \
|
||||
__RV_FSTORE(FREG(5), __fpu_context, 5 << LOG_FPREGBYTES); \
|
||||
__RV_FSTORE(FREG(6), __fpu_context, 6 << LOG_FPREGBYTES); \
|
||||
__RV_FSTORE(FREG(7), __fpu_context, 7 << LOG_FPREGBYTES); \
|
||||
__RV_FSTORE(FREG(10), __fpu_context, 8 << LOG_FPREGBYTES); \
|
||||
__RV_FSTORE(FREG(11), __fpu_context, 9 << LOG_FPREGBYTES); \
|
||||
__RV_FSTORE(FREG(12), __fpu_context, 10 << LOG_FPREGBYTES); \
|
||||
__RV_FSTORE(FREG(13), __fpu_context, 11 << LOG_FPREGBYTES); \
|
||||
__RV_FSTORE(FREG(14), __fpu_context, 12 << LOG_FPREGBYTES); \
|
||||
__RV_FSTORE(FREG(15), __fpu_context, 13 << LOG_FPREGBYTES); \
|
||||
__RV_FSTORE(FREG(16), __fpu_context, 14 << LOG_FPREGBYTES); \
|
||||
__RV_FSTORE(FREG(17), __fpu_context, 15 << LOG_FPREGBYTES); \
|
||||
__RV_FSTORE(FREG(28), __fpu_context, 16 << LOG_FPREGBYTES); \
|
||||
__RV_FSTORE(FREG(29), __fpu_context, 17 << LOG_FPREGBYTES); \
|
||||
__RV_FSTORE(FREG(30), __fpu_context, 18 << LOG_FPREGBYTES); \
|
||||
__RV_FSTORE(FREG(31), __fpu_context, 19 << LOG_FPREGBYTES);
|
||||
|
||||
/**
|
||||
* \brief Restore necessary fpu registers from variables for interrupt nesting
|
||||
* \details
|
||||
* This macro is used restore necessary fpu registers and FCSR from pre-defined variables
|
||||
* in \ref SAVE_FPU_CONTEXT macro.
|
||||
* \remarks
|
||||
* - It need to be used together with \ref SAVE_FPU_CONTEXT
|
||||
*/
|
||||
#define RESTORE_FPU_CONTEXT() \
|
||||
__RV_FLOAD(FREG(0), __fpu_context, 0 << LOG_FPREGBYTES); \
|
||||
__RV_FLOAD(FREG(1), __fpu_context, 1 << LOG_FPREGBYTES); \
|
||||
__RV_FLOAD(FREG(2), __fpu_context, 2 << LOG_FPREGBYTES); \
|
||||
__RV_FLOAD(FREG(3), __fpu_context, 3 << LOG_FPREGBYTES); \
|
||||
__RV_FLOAD(FREG(4), __fpu_context, 4 << LOG_FPREGBYTES); \
|
||||
__RV_FLOAD(FREG(5), __fpu_context, 5 << LOG_FPREGBYTES); \
|
||||
__RV_FLOAD(FREG(6), __fpu_context, 6 << LOG_FPREGBYTES); \
|
||||
__RV_FLOAD(FREG(7), __fpu_context, 7 << LOG_FPREGBYTES); \
|
||||
__RV_FLOAD(FREG(10), __fpu_context, 8 << LOG_FPREGBYTES); \
|
||||
__RV_FLOAD(FREG(11), __fpu_context, 9 << LOG_FPREGBYTES); \
|
||||
__RV_FLOAD(FREG(12), __fpu_context, 10 << LOG_FPREGBYTES); \
|
||||
__RV_FLOAD(FREG(13), __fpu_context, 11 << LOG_FPREGBYTES); \
|
||||
__RV_FLOAD(FREG(14), __fpu_context, 12 << LOG_FPREGBYTES); \
|
||||
__RV_FLOAD(FREG(15), __fpu_context, 13 << LOG_FPREGBYTES); \
|
||||
__RV_FLOAD(FREG(16), __fpu_context, 14 << LOG_FPREGBYTES); \
|
||||
__RV_FLOAD(FREG(17), __fpu_context, 15 << LOG_FPREGBYTES); \
|
||||
__RV_FLOAD(FREG(28), __fpu_context, 16 << LOG_FPREGBYTES); \
|
||||
__RV_FLOAD(FREG(29), __fpu_context, 17 << LOG_FPREGBYTES); \
|
||||
__RV_FLOAD(FREG(30), __fpu_context, 18 << LOG_FPREGBYTES); \
|
||||
__RV_FLOAD(FREG(31), __fpu_context, 19 << LOG_FPREGBYTES); \
|
||||
__set_FCSR(__fcsr);
|
||||
#else
|
||||
#define SAVE_FPU_CONTEXT()
|
||||
#define RESTORE_FPU_CONTEXT()
|
||||
#endif /* __FPU_PRESENT > 0 */
|
||||
/** @} */ /* End of Doxygen Group NMSIS_Core_FPU_Functions */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif /* __CORE_FEATURE_FPU_H__ */
|
||||
@@ -0,0 +1,603 @@
|
||||
/*
|
||||
* Copyright (c) 2019 Nuclei Limited. All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
#ifndef __CORE_FEATURE_IINFO_H__
|
||||
#define __CORE_FEATURE_IINFO_H__
|
||||
/*!
|
||||
* @file core_feature_iinfo.h
|
||||
* @brief IREGION INFO feature API header file for Nuclei N/NX Core
|
||||
* @remarks Most registers in IREGION INFO are used to convey CPU information.
|
||||
* It is recommended to inspect or view this information using the `cpuinfo`
|
||||
* application. The macros and functions defined in this file provide only the
|
||||
* most commonly used operations and do not offer comprehensive support for
|
||||
* inspecting all available information.
|
||||
*/
|
||||
/*
|
||||
* IREGION INFO Configuration Macro:
|
||||
*
|
||||
* 1. __IINFO_BASE: Base address of the IREGION INFO
|
||||
*
|
||||
*/
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "core_feature_base.h"
|
||||
|
||||
/**
|
||||
* IREGION may not exist in legacy Nuclei CPU, so IREGION INFO related
|
||||
* APIs are only available when __IINFO_BASEADDR is defined
|
||||
*/
|
||||
#ifdef __IINFO_BASEADDR
|
||||
|
||||
/**
|
||||
* \defgroup NMSIS_Core_IINFO_Registers Register Define and Type Definitions Of IINFO
|
||||
* \ingroup NMSIS_Core_Registers
|
||||
* \brief Type definitions and defines for iinfo registers.
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* \brief Union type to access MCMO_INFO register.
|
||||
*/
|
||||
typedef union {
|
||||
struct {
|
||||
__IM uint32_t cmo_cfg:1; /*!< bit: 0 CMO exist */
|
||||
__IM uint32_t cmo_pft:1; /*!< bit: 1 CMO has prefetch */
|
||||
__IM uint32_t cmo_size:4; /*!< bit: 2..5 cache block size */
|
||||
__IM uint32_t cbozero_size:4; /*!< bit: 6..9 cache block size of cbo.zero */
|
||||
uint32_t :22; /*!< bit: 10..31 Reserved 0 */
|
||||
} b; /*!< Structure used for bit access */
|
||||
uint32_t d; /*!< Type used for register data access */
|
||||
} IINFO_MCMO_INFO_Type;
|
||||
|
||||
/**
|
||||
* \brief Union type to access ISA_SUPPORT0 register.
|
||||
*/
|
||||
typedef union {
|
||||
struct {
|
||||
__IM uint32_t exist:1; /*!< bit: 0 whether this register is valid */
|
||||
__IM uint32_t vector:1; /*!< bit: 1 support Vector extension */
|
||||
__IM uint32_t vector_b:1; /*!< bit: 2 support Vector-B extension */
|
||||
__IM uint32_t vector_k:1; /*!< bit: 3 support Vector-K extension */
|
||||
__IM uint32_t smepmp:1; /*!< bit: 4 support Smepmp extension */
|
||||
__IM uint32_t sscofpmf:1; /*!< bit: 5 support Sscofpmf extension */
|
||||
__IM uint32_t zfh:1; /*!< bit: 6 support Zfh extension */
|
||||
__IM uint32_t zfhmin:1; /*!< bit: 7 support Zfhmin extension */
|
||||
__IM uint32_t zfa:1; /*!< bit: 8 support Zfa extension */
|
||||
__IM uint32_t svnapot:1; /*!< bit: 9 support Svnapot extension */
|
||||
__IM uint32_t svpbmt:1; /*!< bit: 10 support Svpbmt extension */
|
||||
__IM uint32_t svinval:1; /*!< bit: 11 support Svinval extension */
|
||||
__IM uint32_t bf16:1; /*!< bit: 12 support Bf16 extension */
|
||||
__IM uint32_t zve32x:1; /*!< bit: 13 support Zve32x extension */
|
||||
__IM uint32_t zve32f:1; /*!< bit: 14 support Zve32f extension */
|
||||
__IM uint32_t zve64x:1; /*!< bit: 15 support Zve64x extension */
|
||||
__IM uint32_t zve64f:1; /*!< bit: 16 support Zve64f extension */
|
||||
__IM uint32_t zve64d:1; /*!< bit: 17 support Zve64d extension */
|
||||
__IM uint32_t zimop:1; /*!< bit: 18 support Zimop extension */
|
||||
__IM uint32_t zcmop:1; /*!< bit: 19 support Zomop extension */
|
||||
__IM uint32_t zicond:1; /*!< bit: 20 support Zicond extension */
|
||||
__IM uint32_t zihintntl:1; /*!< bit: 21 support Zihintntl extension */
|
||||
__IM uint32_t zihintpause:1; /*!< bit: 22 support Zihintpause extension */
|
||||
__IM uint32_t zvfh:1; /*!< bit: 23 support Zvfh extension */
|
||||
__IM uint32_t zvfhmin:1; /*!< bit: 24 support Zvfhmin extension */
|
||||
__IM uint32_t smrnmi:1; /*!< bit: 25 support Smrnmi extension */
|
||||
__IM uint32_t zihpm:1; /*!< bit: 26 support Zihpm extension */
|
||||
__IM uint32_t smcntrpmf:1; /*!< bit: 27 support Smcntrpmf extension */
|
||||
__IM uint32_t zicntr:1; /*!< bit: 28 support Zicntr extension */
|
||||
__IM uint32_t zawrs:1; /*!< bit: 29 support Zawrs extension */
|
||||
uint32_t :2; /*!< bit: 30..31 reserved */
|
||||
} b; /*!< Structure used for bit access */
|
||||
uint32_t d; /*!< Type used for register data access */
|
||||
} IINFO_ISA_SUPPORT0_Type;
|
||||
|
||||
/**
|
||||
* \brief Union type to access ISA_SUPPORT1 register.
|
||||
*/
|
||||
typedef union {
|
||||
struct {
|
||||
__IM uint32_t exist:1; /*!< bit: 0 whether this register is valid */
|
||||
__IM uint32_t ssqosid:1; /*!< bit: 1 support Ssqosid extension */
|
||||
__IM uint32_t zicflip:1; /*!< bit: 2 support zicflip extension */
|
||||
__IM uint32_t zicfiss:1; /*!< bit: 3 support zicfiss extension */
|
||||
__IM uint32_t smctr:1; /*!< bit: 4 support Smctr extension */
|
||||
__IM uint32_t zacas:1; /*!< bit: 5 support Zacas extension */
|
||||
__IM uint32_t zabha:1; /*!< bit: 6 support Zabha extension */
|
||||
__IM uint32_t smdbltrp:1; /*!< bit: 7 support Smdbltrp extension */
|
||||
__IM uint32_t ssdbltrp:1; /*!< bit: 8 support Ssdbltrp extension */
|
||||
__IM uint32_t smcdeleg:1; /*!< bit: 9 support Smcdeleg extension */
|
||||
__IM uint32_t smmpm:1; /*!< bit: 10 support Smmpm extension */
|
||||
__IM uint32_t smnpm:1; /*!< bit: 11 support Smnpm extension */
|
||||
__IM uint32_t ssnpm:1; /*!< bit: 12 support Ssnpm extension */
|
||||
__IM uint32_t smstateen:1; /*!< bit: 13 support Smstateen extension */
|
||||
__IM uint32_t sstateen:1; /*!< bit: 14 support Sstateen extension */
|
||||
__IM uint32_t smcsrind:1; /*!< bit: 15 support Smcsrind extension */
|
||||
__IM uint32_t sscsrind:1; /*!< bit: 16 support Sscsrind extension */
|
||||
__IM uint32_t svadu:1; /*!< bit: 17 support Svadu extension */
|
||||
uint32_t :14; /*!< bit: 18..31 reserved */
|
||||
} b; /*!< Structure used for bit access */
|
||||
uint32_t d; /*!< Type used for register data access */
|
||||
} IINFO_ISA_SUPPORT1_Type;
|
||||
|
||||
/**
|
||||
* \brief Union type to access PERFORMANCE_CFG0 register.
|
||||
*/
|
||||
typedef union {
|
||||
struct {
|
||||
__IM uint32_t exist:1; /*!< bit: 0 whether this register is valid */
|
||||
__IM uint32_t fpu_cycle:5; /*!< bit: 1..5 fpu cycle count */
|
||||
__IM uint32_t high_div:1; /*!< bit: 6 high performance divider */
|
||||
__IM uint32_t dcache_2stage:1; /*!< bit: 7 dcache 2 stage */
|
||||
__IM uint32_t delay_branch_flush:1; /*!< bit: 8 delay branch flash */
|
||||
__IM uint32_t bus_type:3; /*!< bit: 9..11 memory bus protocol type */
|
||||
__IM uint32_t dual_issue:1; /*!< bit: 12 dual issue */
|
||||
__IM uint32_t cross_4k:1; /*!< bit: 13 cross 4k */
|
||||
__IM uint32_t dlm_2stage:1; /*!< bit: 14 DLM 2 stage */
|
||||
__IM uint32_t lsu_cut_fwd:1; /*!< bit: 15 LSU cut forwarding */
|
||||
__IM uint32_t dsp_cycle:4; /*!< bit: 16..19 DSP cycle */
|
||||
__IM uint32_t ifu_cut_timing:1; /*!< bit: 20 IFU cut timing */
|
||||
__IM uint32_t mem_cut_timing:1; /*!< bit: 21 MEM cut timing */
|
||||
__IM uint32_t dcache_prefetch:1; /*!< bit: 22 dcache prefetch */
|
||||
__IM uint32_t dcache_lbuf_num:5; /*!< bit: 23..27 dcache line buffer number */
|
||||
__IM uint32_t mul_cyc:3; /*!< bit: 28..30 multiplier cycle */
|
||||
uint32_t :1; /*!< bit: 31 reserved */
|
||||
} b; /*!< Structure used for bit access */
|
||||
uint32_t d; /*!< Type used for register data access */
|
||||
} IINFO_PERFORMANCE_CFG0_Type;
|
||||
|
||||
/**
|
||||
* \brief Union type to access PERFORMANCE_CFG1 register.
|
||||
*/
|
||||
typedef union {
|
||||
struct {
|
||||
__IM uint32_t exist:1; /*!< bit: 0 whether this register is valid */
|
||||
__IM uint32_t vfpu_cyc:5; /*!< bit: 1..5 Vector FPU cycle */
|
||||
__IM uint32_t bht_entry_width:5; /*!< bit: 6..10 BHT entry width */
|
||||
__IM uint32_t high_performance:1; /*!< bit: 11 high performance */
|
||||
__IM uint32_t agu_quick_forward:1; /*!< bit: 12 agu quick forward */
|
||||
__IM uint32_t cau_fwd:1; /*!< bit: 13 crypto instruction forward */
|
||||
__IM uint32_t hpm_ver:2; /*!< bit: 14..15 HPM version */
|
||||
uint32_t :16; /*!< bit: 16..31 reserved */
|
||||
} b; /*!< Structure used for bit access */
|
||||
uint32_t d; /*!< Type used for register data access */
|
||||
} IINFO_PERFORMANCE_CFG1_Type;
|
||||
|
||||
/**
|
||||
* \brief Union type to access PFL1DCTRL1 register.
|
||||
*/
|
||||
typedef union {
|
||||
struct {
|
||||
__IOM uint32_t l1d_ena:1; /*!< bit: 0 L1 dcache prefetch enable */
|
||||
__IOM uint32_t cc_ena:1; /*!< bit: 1 cluster cache prefetch enable */
|
||||
__IOM uint32_t scalar_ena:1; /*!< bit: 2 scalar pipeline prefetch enable */
|
||||
__IOM uint32_t vector_ena:1; /*!< bit: 3 vector pipeline prefetch enable */
|
||||
__IOM uint32_t write_pref_ena:1; /*!< bit: 4 store prefetch enable */
|
||||
__IOM uint32_t cross_page_pref_ena:1; /*!< bit: 5 prefetch cross page enable */
|
||||
__IOM uint32_t mmu_ena:1; /*!< bit: 6 mmu prefetch enable */
|
||||
__IOM uint32_t pl2_ena:1; /*!< bit: 7 private L2 prefetch enable */
|
||||
__IOM uint32_t pref_conflict_stop_th:4; /*!< bit: 8..11 prefetch inc counter stop threshold */
|
||||
__IOM uint32_t pref_conflict_decr_sel:3; /*!< bit: 12..14 prefetch num to dec counter */
|
||||
uint32_t :17; /*!< bit: 15..31 reserved */
|
||||
} b; /*!< Structure used for bit access */
|
||||
struct {
|
||||
/**
|
||||
* \brief 0..7 prefetch enable level
|
||||
* \details Writing to this bit field may use the `sb` instruction (write only one byte),
|
||||
* which is not allowed for IINFO registers. So this bit field is read-only here,
|
||||
* but actually it can be written. To write this bit field, you should write the
|
||||
* whole 32-bit register
|
||||
* \sa
|
||||
* - \ref IINFO_SetPrefetchLevel
|
||||
*
|
||||
* The recommended values are:
|
||||
* - 0x3F: Enable all prefetch except MMU and private L2 cache prefetch.
|
||||
* - 0xBF: Enable all prefetch except MMU prefetch.
|
||||
* Enabling **cross page prefetch** in bare-metal environment is always recommended
|
||||
* for better performance.
|
||||
*/
|
||||
__IM uint32_t level:8;
|
||||
__IM uint32_t pref_conflict_stop_th:4; /*!< bit: 8..11 prefetch inc counter stop threshold */
|
||||
__IM uint32_t pref_conflict_decr_sel:3; /*!< bit: 12..14 prefetch num to dec counter */
|
||||
uint32_t :17; /*!< bit: 15..31 reserved */
|
||||
} lv; /*!< Structure used for enable level field setup */
|
||||
uint32_t d; /*!< Type used for register data access */
|
||||
} IINFO_PFL1DCTRL1_Type;
|
||||
|
||||
#define IINFO_PFL1DCTRL1_LEVEL_Pos (1UL << 0) /* IINFO PFL1DCTRL1 level position */
|
||||
#define IINFO_PFL1DCTRL1_LEVEL_Msk (0xFFUL << IINFO_PFL1DCTRL1_LEVEL_Pos) /* IINFO PFL1DCTRL1 level mask */
|
||||
|
||||
#define IINFO_PFL1DCTRL1_DISABLE (0UL) /*!< Disable all prefetch */
|
||||
#define IINFO_PFL1DCTRL1_L1D_ENA (1UL << 0) /*!< L1 dcache prefetch enable mask */
|
||||
#define IINFO_PFL1DCTRL1_CC_ENA (1UL << 1) /*!< Cluster cache prefetch enable mask */
|
||||
#define IINFO_PFL1DCTRL1_SCALAR_ENA (1UL << 2) /*!< Scalar pipeline prefetch enable mask */
|
||||
#define IINFO_PFL1DCTRL1_VECTOR_ENA (1UL << 3) /*!< Vector pipeline prefetch enable mask */
|
||||
#define IINFO_PFL1DCTRL1_WRITE_PREF_ENA (1UL << 4) /*!< Store prefetch enable mask */
|
||||
#define IINFO_PFL1DCTRL1_CROSS_PAGE_PREF_ENA (1UL << 5) /*!< Cross page prefetch enable mask */
|
||||
#define IINFO_PFL1DCTRL1_MMU_PREF_ENA (1UL << 6) /*!< MMU prefetch enable mask */
|
||||
#define IINFO_PFL1DCTRL1_PL2_ENA (1UL << 7) /*!< Private L2 prefetch enable mask */
|
||||
|
||||
/**
|
||||
* \brief Union type to access PFL1DCTRL2 register.
|
||||
*/
|
||||
typedef union {
|
||||
struct {
|
||||
__IOM uint32_t degree_incr_th:6; /*!< bit: 0..5 prefetch degree threshold of incr */
|
||||
__IOM uint32_t degree_decr_th:6; /*!< bit: 6..11 prefetch degree threshold of decr */
|
||||
__IOM uint32_t next_line_ena_th:4; /*!< bit: 12..15 next line enable threshold */
|
||||
__IOM uint32_t write_noalloc_l1_th:2; /*!< bit: 16..17 see ISA doc */
|
||||
__IOM uint32_t write_noalloc_l2_th:2; /*!< bit: 18..19 see ISA doc */
|
||||
uint32_t :12; /*!< bit: 20..31 reserved */
|
||||
} b; /*!< Structure used for bit access */
|
||||
uint32_t d; /*!< Type used for register data access */
|
||||
} IINFO_PFL1DCTRL2_Type;
|
||||
|
||||
/**
|
||||
* \brief Union type to access MERGEL1DCTRL register.
|
||||
*/
|
||||
typedef union {
|
||||
struct {
|
||||
__IOM uint32_t ws_tmout_max:12; /*!< bit: 0..11 write streaming tmout cnt max value */
|
||||
uint32_t :4; /*!< bit: 12..15 reserved */
|
||||
__IOM uint32_t nc_tmout_max:8; /*!< bit: 16..23 non-cacheable tmout cnt max value */
|
||||
__IOM uint32_t dev_store_early_ret: 1; /*!< bit: 24 whether device region store is blocking */
|
||||
uint32_t :7; /*!< bit: 25..31 reserved */
|
||||
} b; /*!< Structure used for bit access */
|
||||
uint32_t d; /*!< Type used for register data access */
|
||||
} IINFO_MERGEL1DCTRL_Type;
|
||||
|
||||
/**
|
||||
* \brief Union type to access SAFETY_CTRL register.
|
||||
*/
|
||||
typedef union {
|
||||
struct {
|
||||
__IOM uint32_t reg_prot_chck_en:2; /*!< bit: 0..1 register protect check enable */
|
||||
uint32_t :30; /*!< bit: 2..31 reserved */
|
||||
} b; /*!< Structure used for bit access */
|
||||
uint32_t d; /*!< Type used for register data access */
|
||||
} IINFO_SAFETY_CTRL_Type;
|
||||
|
||||
/**
|
||||
* \brief Union type to access ACCESS_CTRL register.
|
||||
*/
|
||||
typedef union {
|
||||
struct {
|
||||
uint32_t :1; /*!< bit: 0 reversed */
|
||||
__IOM uint32_t pf_access: 1; /*!< bit: 1 s-mode register access, 0 is enable */
|
||||
__IOM uint32_t cache_csr_access: 1; /*!< bit: 2 s-mode cache csr access */
|
||||
__IOM uint32_t pma_csr_access: 1; /*!< bit: 3 s-mode pma csr access */
|
||||
uint32_t :28; /*!< bit: 4..31 reserved */
|
||||
} b; /*!< Structure used for bit access */
|
||||
uint32_t d; /*!< Type used for register data access */
|
||||
} IINFO_ACCESS_CTRL_Type;
|
||||
|
||||
/**
|
||||
* \brief Union type to access PFL1DCTRL3 register.
|
||||
*/
|
||||
typedef union {
|
||||
struct {
|
||||
__IOM uint32_t max_stream_l1_degree:4; /*!< bit: 0..3 mat stream prefetch L1 degree */
|
||||
uint32_t :1; /*!< bit: 4 reserved */
|
||||
__IOM uint32_t max_stream_l2_degree:7; /*!< bit: 5..11 next line enable threshold */
|
||||
uint32_t :4; /*!< bit: 12..15 reserved */
|
||||
__IOM uint32_t max_stride_cplx_l1_degree:4; /*!< bit: 16..19 the max stride/cplx pref L1 degree */
|
||||
uint32_t :1; /*!< bit: 20 reserved */
|
||||
__IOM uint32_t max_stride_cplx_l2_degree:7; /*!< bit: 21..27 the max stride/cplx pref L2 degree */
|
||||
uint32_t :4; /*!< bit: 28..31 reserved */
|
||||
} b; /*!< Structure used for bit access */
|
||||
uint32_t d; /*!< Type used for register data access */
|
||||
} IINFO_PFL1DCTRL3_Type;
|
||||
|
||||
/**
|
||||
* \brief Union type to access PFL1DCTRL4 register.
|
||||
*/
|
||||
typedef union {
|
||||
struct {
|
||||
__IOM uint32_t pf_enable:1; /*!< bit: 0 prefetch overall enable */
|
||||
__IOM uint32_t cc_short_enable:1; /*!< bit: 1 cluster cache short enable */
|
||||
uint32_t :30; /*!< bit: 2..31 reserved */
|
||||
} b; /*!< Structure used for bit access */
|
||||
uint32_t d; /*!< Type used for register data access */
|
||||
} IINFO_PFL1DCTRL4_Type;
|
||||
|
||||
/**
|
||||
* \brief Union type to access PFL1INFO register.
|
||||
*/
|
||||
typedef union {
|
||||
struct {
|
||||
__IM uint32_t pf_cfg:8; /*!< bit: 0..7 prefetch configuration */
|
||||
__IM uint32_t l2_pf_lbuf_num:8; /*!< bit: 8..15 L2 prefetch req address buf number */
|
||||
__IM uint32_t l2_pf_dbuf_num:8; /*!< bit: 16..23 L2 prefetch data buf number */
|
||||
__IM uint32_t pf_ver:8; /*!< bit: 24..31 prefetch version */
|
||||
} b; /*!< Structure used for bit access */
|
||||
uint32_t d; /*!< Type used for register data access */
|
||||
} IINFO_PFL1INFO_Type;
|
||||
|
||||
/**
|
||||
* \brief Union type to access ECC_INJ_WAY register.
|
||||
*/
|
||||
typedef union {
|
||||
struct {
|
||||
uint32_t inject_way:8; /*!< bit: 0..7 each bit corresponds to a way, one-hot, when inject ecc error, data will fill into the way which is 1 */
|
||||
uint32_t :22; /*!< bit: 8..29 reserved */
|
||||
uint32_t security_mode:1; /*!< bit: 30 indicate the current security mode, 0 for sec mode, 1 for non-sec mode */
|
||||
uint32_t precise_ecc_inject:1; /*!< bit: 31 rtl support the feature of precise ecc inject */
|
||||
} b; /*!< Structure used for bit access */
|
||||
uint32_t d; /*!< Type used for register data access */
|
||||
} IINFO_ECC_INJ_WAY_Type;
|
||||
|
||||
/* IREGION INFO Memory-Mapped Register Type*/
|
||||
typedef struct {
|
||||
__IM uint32_t mpasize; /*!< offset 0x0000 */
|
||||
__IM IINFO_MCMO_INFO_Type cmo_info; /*!< offset 0x0004 */
|
||||
__IM uint32_t sec_base_addr_lo; /*!< offset 0x0008 */
|
||||
__IM uint32_t sec_base_addr_hi; /*!< offset 0x000C */
|
||||
__IM uint32_t sec_cfg_info; /*!< offset 0x0010 */
|
||||
__IM uint32_t reserved0[4]; /*!< offset 0x0014 */
|
||||
__IM uint32_t mvlm_cfg_lo; /*!< offset 0x0024 */
|
||||
__IM uint32_t mvlm_cfg_hi; /*!< offset 0x0028 */
|
||||
__IM uint32_t flash_base_addr_lo; /*!< offset 0x002C */
|
||||
__IM uint32_t flash_base_addr_hi; /*!< offset 0x0030 */
|
||||
__IM uint32_t reserved1[7]; /*!< offset 0x0034 */
|
||||
__IM uint32_t vpu_cfg_info; /*!< offset 0x0050 */
|
||||
__IOM uint32_t mem_region0_cfg_lo; /*!< offset 0x0054 */
|
||||
__IM uint32_t mem_region0_cfg_hi; /*!< offset 0x0058 */
|
||||
__IOM uint32_t mem_region1_cfg_lo; /*!< offset 0x005c */
|
||||
__IM uint32_t mem_region1_cfg_hi; /*!< offset 0x0060 */
|
||||
uint32_t reserved2[3]; /*!< offset 0x0064 */
|
||||
__IM IINFO_ISA_SUPPORT0_Type isa_support0; /*!< offset 0x0070 */
|
||||
__IM IINFO_ISA_SUPPORT1_Type isa_support1; /*!< offset 0x0074 */
|
||||
uint32_t reserved3[2]; /*!< offset 0x0078 */
|
||||
__IOM uint32_t mcppi_cfg_lo; /*!< offset 0x0080 */
|
||||
__IM uint32_t mcppi_cfg_hi; /*!< offset 0x0084 */
|
||||
__IOM uint32_t mpftctl; /*!< offset 0x0088 */
|
||||
uint32_t reserved4; /*!< offset 0x008C */
|
||||
__IM IINFO_PERFORMANCE_CFG0_Type performance_cfg0; /*!< offset 0x0090 */
|
||||
__IM IINFO_PERFORMANCE_CFG1_Type performance_cfg1; /*!< offset 0x0094 */
|
||||
uint32_t reserved5[26]; /*!< offset 0x0098 */
|
||||
__IOM IINFO_PFL1DCTRL1_Type pfl1dctrl1; /*!< offset 0x0100 */
|
||||
__IOM IINFO_PFL1DCTRL2_Type pfl1dctrl2; /*!< offset 0x0104 */
|
||||
__IOM IINFO_MERGEL1DCTRL_Type mergel1dctrl; /*!< offset 0x0108 */
|
||||
uint32_t reserved6; /*!< offset 0x010C */
|
||||
__IOM IINFO_SAFETY_CTRL_Type safety_ctrl; /*!< offset 0x0110 */
|
||||
__IOM IINFO_ACCESS_CTRL_Type access_ctrl; /*!< offset 0x0114 */
|
||||
uint32_t reserved7[2]; /*!< offset 0x0118 */
|
||||
__IOM IINFO_PFL1DCTRL3_Type pfl1dctrl3; /*!< offset 0x0120 */
|
||||
__IOM IINFO_PFL1DCTRL4_Type pfl1dctrl4; /*!< offset 0x0124 */
|
||||
__IM IINFO_PFL1INFO_Type pfl1info; /*!< offset 0x0128 */
|
||||
uint32_t reserved8[27]; /*!< offset 0x012C */
|
||||
__IOM uint32_t crc_rf0; /*!< offset 0x0198 */
|
||||
__IOM uint32_t crc_rf1; /*!< offset 0x019C */
|
||||
__IOM uint32_t crc_fp0; /*!< offset 0x01A0 */
|
||||
__IM uint32_t etrace_info; /*!< offset 0x01A4 */
|
||||
__IOM uint32_t ecc_inj_addr_lo; /*!< offset 0x01A8 */
|
||||
__IOM uint32_t ecc_inj_addr_hi; /*!< offset 0x01AC */
|
||||
__IOM IINFO_ECC_INJ_WAY_Type ecc_inj_way; /*!< offset 0x01B0 */
|
||||
uint32_t reserved9[83]; /*!< offset 0x01B4 */
|
||||
__IOM uint32_t mem_crc_x22_lo; /*!< offset 0x0300 */
|
||||
__IOM uint32_t mem_crc_x22_hi; /*!< offset 0x0304 */
|
||||
__IOM uint32_t mem_crc_x23_lo; /*!< offset 0x0308 */
|
||||
__IOM uint32_t mem_crc_x23_hi; /*!< offset 0x030C */
|
||||
__IOM uint32_t mem_crc_f23_lo; /*!< offset 0x0310 */
|
||||
__IOM uint32_t mem_crc_f23_hi; /*!< offset 0x0314 */
|
||||
} IINFO_Type;
|
||||
|
||||
/* IREGION INFO Memory mapping of Device */
|
||||
#define IINFO_BASE __IINFO_BASEADDR /*!< IINFO Base Address */
|
||||
#define IINFO ((IINFO_Type *)IINFO_BASE) /*!< IINFO configuration struct */
|
||||
|
||||
/**
|
||||
* \brief Enum type to distinguish HPM version.
|
||||
*/
|
||||
typedef enum {
|
||||
IINFO_HPM_VER_UNKNOWN = 0, /*!< HPM version unknown */
|
||||
IINFO_HPM_VER_1, /*!< HPM version 1 */
|
||||
IINFO_HPM_VER_2, /*!< HPM version 2 */
|
||||
IINFO_HPM_VER_MAX /*!< Max number of HPM version */
|
||||
} IINFO_HPM_VER_Type;
|
||||
|
||||
/** @} */ /* end of group NMSIS_Core_IINFO_Registers */
|
||||
|
||||
/**
|
||||
* \defgroup NMSIS_Core_IINFO_Functions IINFO Functions
|
||||
* \ingroup NMSIS_Core
|
||||
* \brief IINFO related functions
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* \brief Check if CMO is supported
|
||||
* \details Checks whether the CMO feature is supported by reading the cmo_cfg bit
|
||||
* from the CMO_INFO register.
|
||||
* \return 1 if CMO is supported, 0 otherwise
|
||||
*/
|
||||
__STATIC_FORCEINLINE int32_t IINFO_IsCMOSupported(void)
|
||||
{
|
||||
return IINFO->cmo_info.b.cmo_cfg;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Check if CMO prefetch is supported
|
||||
* \details Checks whether the CMO prefetch feature is supported
|
||||
* by reading the cmo_pft bit from the CMO_INFO register.
|
||||
* \return 1 if CMO prefetch is supported, 0 otherwise
|
||||
*/
|
||||
__STATIC_FORCEINLINE int32_t IINFO_IsCMOPrefetchSupported(void)
|
||||
{
|
||||
return IINFO->cmo_info.b.cmo_cfg && IINFO->cmo_info.b.cmo_pft;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Get Hardware Performance Monitor (HPM) version
|
||||
* \details Gets the version of the Hardware Performance Monitor (HPM) feature
|
||||
* by reading the hpm_ver bits from the PERFORMANCE_CFG1 register.
|
||||
* If the PERFORMANCE_CFG1 register does not exist, returns IINFO_HPM_VER_UNKNOWN.
|
||||
* \return HPM version as IINFO_HPM_VER_Type enum value
|
||||
*/
|
||||
__STATIC_FORCEINLINE IINFO_HPM_VER_Type IINFO_GetHPMVersion(void)
|
||||
{
|
||||
if (!IINFO->performance_cfg1.b.exist) {
|
||||
return IINFO_HPM_VER_UNKNOWN;
|
||||
}
|
||||
return (IINFO_HPM_VER_Type)IINFO->performance_cfg1.b.hpm_ver;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Set prefetch enable level bits
|
||||
* \details This function writes the specified bitmask to the prefetch enable field
|
||||
* (bits 0–7) of the PFL1DCTRL1 register. Each bit corresponds to a specific
|
||||
* prefetch, and enabling a bit activates it.
|
||||
*
|
||||
* To construct the \p val argument, use the predefined bitmask macros
|
||||
* (e.g., \c IINFO_PFL1DCTRL1_LEVEL_L1D_ENA). Multiple prefetch can be
|
||||
* enabled simultaneously by bitwise-ORing their respective masks.
|
||||
*
|
||||
* \param[in] val Bitmask value for prefetch enable bits (bits 0–7 of PFL1DCTRL1).
|
||||
* Only the lower 8 bits are used; higher bits are ignored.
|
||||
* \sa
|
||||
* - \ref IINFO_GetPrefetchLevel
|
||||
* - \ref IINFO_PFL1DCTRL1_DISABLE
|
||||
* - \ref IINFO_PFL1DCTRL1_L1D_ENA
|
||||
* - \ref IINFO_PFL1DCTRL1_CC_ENA
|
||||
* - \ref IINFO_PFL1DCTRL1_SCALAR_ENA
|
||||
* - \ref IINFO_PFL1DCTRL1_VECTOR_ENA
|
||||
* - \ref IINFO_PFL1DCTRL1_WRITE_PREF_ENA
|
||||
* - \ref IINFO_PFL1DCTRL1_CROSS_PAGE_PREF_ENA
|
||||
* - \ref IINFO_PFL1DCTRL1_MMU_PREF_ENA
|
||||
* - \ref IINFO_PFL1DCTRL1_PL2_ENA
|
||||
*
|
||||
* \example
|
||||
* \code
|
||||
* // Enable all prefetch except MMU and private L2 (PL2)
|
||||
* IINFO_SetPrefetchLevel(IINFO_PFL1DCTRL1_L1D_ENA |
|
||||
* IINFO_PFL1DCTRL1_CC_ENA |
|
||||
* IINFO_PFL1DCTRL1_SCALAR_ENA |
|
||||
* IINFO_PFL1DCTRL1_VECTOR_ENA |
|
||||
* IINFO_PFL1DCTRL1_WRITE_PREF_ENA |
|
||||
* IINFO_PFL1DCTRL1_CROSS_PAGE_PREF_ENA);
|
||||
* \endcode
|
||||
*/
|
||||
__STATIC_FORCEINLINE void IINFO_SetPrefetchLevel(uint32_t val)
|
||||
{
|
||||
IINFO->pfl1dctrl1.d = (IINFO->pfl1dctrl1.d & ~IINFO_PFL1DCTRL1_LEVEL_Msk) |
|
||||
_VAL2FLD(IINFO_PFL1DCTRL1_LEVEL, val);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Get prefetch enable level bits
|
||||
* \details Gets the prefetch enable level bits from the PFL1DCTRL1 register using the enable field.
|
||||
* \return Current value of prefetch enable bits (bits 0-7)
|
||||
* \sa
|
||||
* - \ref IINFO_SetPrefetchLevel
|
||||
*/
|
||||
__STATIC_FORCEINLINE uint32_t IINFO_GetPrefetchLevel(void)
|
||||
{
|
||||
return IINFO->pfl1dctrl1.lv.level;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Set PFL1DCTRL2 register value
|
||||
* \details Sets the value of the PFL1DCTRL2 register.
|
||||
* \param val Value to write to the PFL1DCTRL2 register
|
||||
*/
|
||||
__STATIC_FORCEINLINE void IINFO_SetPFL1DCTRL2(uint32_t val)
|
||||
{
|
||||
IINFO->pfl1dctrl2.d = val;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Get PFL1DCTRL2 register value
|
||||
* \details Gets the current value of the PFL1DCTRL2 register.
|
||||
* \return Current value of the PFL1DCTRL2 register
|
||||
*/
|
||||
__STATIC_FORCEINLINE uint32_t IINFO_GetPFL1DCTRL2(void)
|
||||
{
|
||||
return IINFO->pfl1dctrl2.d;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Set PFL1DCTRL3 register value
|
||||
* \details Sets the value of the PFL1DCTRL3 register.
|
||||
* \param val Value to write to the PFL1DCTRL3 register
|
||||
*/
|
||||
__STATIC_FORCEINLINE void IINFO_SetPFL1DCTRL3(uint32_t val)
|
||||
{
|
||||
IINFO->pfl1dctrl3.d = val;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Get PFL1DCTRL3 register value
|
||||
* \details Gets the current value of the PFL1DCTRL3 register.
|
||||
* \return Current value of the PFL1DCTRL3 register
|
||||
*/
|
||||
__STATIC_FORCEINLINE uint32_t IINFO_GetPFL1DCTRL3(void)
|
||||
{
|
||||
return IINFO->pfl1dctrl3.d;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Enable prefetch overall
|
||||
* \details Enables the prefetch overall by setting the pf_enable bit in the PFL1DCTRL4 register.
|
||||
*/
|
||||
__STATIC_FORCEINLINE void IINFO_EnablePrefetchOverall(void)
|
||||
{
|
||||
IINFO->pfl1dctrl4.b.pf_enable = 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Disable prefetch overall
|
||||
* \details Disables the prefetch overall by clearing the pf_enable bit in the PFL1DCTRL4 register.
|
||||
*/
|
||||
__STATIC_FORCEINLINE void IINFO_DisablePrefetchOverall(void)
|
||||
{
|
||||
IINFO->pfl1dctrl4.b.pf_enable = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Check if precise ECC injection is supported
|
||||
* \details Checks whether the precise ECC injection feature is supported
|
||||
* by reading the precise_ecc_inject bit from the ECC_INJ_WAY register.
|
||||
* \return 1 if precise ECC injection is supported, 0 otherwise
|
||||
*/
|
||||
__STATIC_FORCEINLINE int32_t IINFO_IsPreciseECCInjSupported(void)
|
||||
{
|
||||
return IINFO->ecc_inj_way.b.precise_ecc_inject;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Set the address and cache way used for precise ECC injection in ICache, DCache, or CCache
|
||||
* \param addr Target address for ECC error injection
|
||||
* \param way Target cache way for ECC error injection
|
||||
* \remarks The way value must be one-hot. For example, if the cache has 2 ways, valid values are
|
||||
* 0x01 and 0x02; all other values are invalid.
|
||||
*/
|
||||
__STATIC_FORCEINLINE void IINFO_SetPreciseECCInjWay(void *addr, uint8_t way)
|
||||
{
|
||||
unsigned long rv_addr = (unsigned long)addr;
|
||||
IINFO->ecc_inj_addr_lo = (uint32_t)rv_addr;
|
||||
IINFO->ecc_inj_addr_hi = (uint32_t)((uint64_t)rv_addr >> 32);
|
||||
IINFO->ecc_inj_way.b.inject_way = way;
|
||||
}
|
||||
|
||||
/** @} */ /* End of Doxygen Group NMSIS_Core_IINFO_Functions */
|
||||
|
||||
#endif /* #ifdef __IINFO_BASEADDR */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif /* __CORE_FEATURE_IINFO_H__ */
|
||||
|
||||
@@ -0,0 +1,484 @@
|
||||
/*
|
||||
* Copyright (c) 2019 Nuclei Limited. All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* 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 __CORE_FEATURE_PLIC__
|
||||
#define __CORE_FEATURE_PLIC__
|
||||
/*!
|
||||
* @file core_feature_plic.h
|
||||
* @brief PLIC feature API header file for RISC-V Core
|
||||
*/
|
||||
/*
|
||||
* PLIC Feature Configuration Macro:
|
||||
* 1. __PLIC_PRESENT: Define whether Platform Level Interrupt Controller (PLIC) Unit is present or not
|
||||
* * 0: Not present
|
||||
* * 1: Present
|
||||
* 2. __PLIC_BASEADDR: Base address of the PLIC unit.
|
||||
* 3. __PLIC_INTNUM : Define the external interrupt number of PLIC Unit
|
||||
*
|
||||
*/
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "core_feature_base.h"
|
||||
|
||||
#if defined(__PLIC_PRESENT) && (__PLIC_PRESENT == 1)
|
||||
/**
|
||||
* \defgroup NMSIS_Core_PLIC_Registers Register Define and Type Definitions Of PLIC
|
||||
* \ingroup NMSIS_Core_Registers
|
||||
* \brief Type definitions and defines for plic registers.
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
|
||||
/*
|
||||
* PLIC Memory Map (per RISC-V PLIC spec):
|
||||
*
|
||||
* Interrupt Source Priority (per-source, not per-context):
|
||||
* base + 0x000000: Source 0 (reserved, not exist)
|
||||
* base + 0x000004: Source 1 priority
|
||||
* ...
|
||||
* base + 0x000FFC: Source 1023 priority
|
||||
* addr = base + source * 4
|
||||
*
|
||||
* Interrupt Pending Bits (per-source, not per-context):
|
||||
* base + 0x001000: Source 0-31 pending
|
||||
* base + 0x001004: Source 32-63 pending
|
||||
* ...
|
||||
* addr = base + 0x1000 + (source / 32) * 4
|
||||
*
|
||||
* Interrupt Enable Bits (per-context, 0x80 bytes each):
|
||||
* base + 0x002000: Context 0, Source 0-31 enable
|
||||
* base + 0x002080: Context 1, Source 0-31 enable
|
||||
* ...
|
||||
* addr = base + 0x2000 + ctxid * 0x80 + (source / 32) * 4
|
||||
*
|
||||
* Priority Threshold (per-context, 0x1000 bytes each):
|
||||
* base + 0x200000: Context 0 threshold
|
||||
* base + 0x201000: Context 1 threshold
|
||||
* ...
|
||||
* addr = base + 0x200000 + ctxid * 0x1000
|
||||
*
|
||||
* Claim / Complete (per-context, same 4K block as threshold):
|
||||
* base + 0x200004: Context 0 claim/complete
|
||||
* base + 0x201004: Context 1 claim/complete
|
||||
* ...
|
||||
* addr = base + 0x200004 + ctxid * 0x1000
|
||||
* Claim: read returns highest-priority pending interrupt ID
|
||||
* Complete: write interrupt ID to signal handler completion
|
||||
*
|
||||
* Context ID to Hart/Mode mapping (Nuclei RISC-V CPU, not in PLIC spec):
|
||||
* M-mode context ID = hartid * 2 (even: 0, 2, 4, 6, 8)
|
||||
* S-mode context ID = hartid * 2 + 1 (odd: 1, 3, 5, 7, 9)
|
||||
*
|
||||
* Hart 0: M=ctxid 0, S=ctxid 1
|
||||
* Hart 1: M=ctxid 2, S=ctxid 3
|
||||
* Hart 2: M=ctxid 4, S=ctxid 5
|
||||
* Hart 3: M=ctxid 6, S=ctxid 7
|
||||
* Hart 4: M=ctxid 8, S=ctxid 9
|
||||
*
|
||||
* Reference: https://github.com/riscv/riscv-plic-spec
|
||||
*/
|
||||
|
||||
/* Priority: 32 bits per source, addr = base + source * 4 */
|
||||
#define PLIC_PRIORITY_OFFSET _AC(0x0000,UL) /*!< PLIC Priority register offset */
|
||||
#define PLIC_PRIORITY_SHIFT_PER_SOURCE 2 /*!< log2(4), shift per source */
|
||||
|
||||
/* Pending: 1 bit per source, packed 32 per 32-bit register */
|
||||
#define PLIC_PENDING_OFFSET _AC(0x1000,UL) /*!< PLIC Pending register offset */
|
||||
#define PLIC_PENDING_SHIFT_PER_SOURCE 0 /*!< bit index within word */
|
||||
|
||||
/* Enable: 0x80 (128) bytes per context, packed 32 sources per 32-bit word */
|
||||
#define PLIC_ENABLE_OFFSET _AC(0x2000,UL) /*!< PLIC Enable register offset */
|
||||
#define PLIC_ENABLE_SHIFT_PER_CONTEXT 7 /*!< log2(0x80), shift per context */
|
||||
|
||||
/* Threshold: 0x1000 (4096) bytes per context */
|
||||
#define PLIC_THRESHOLD_OFFSET _AC(0x200000,UL) /*!< PLIC Threshold register offset */
|
||||
#define PLIC_CLAIM_OFFSET _AC(0x200004,UL) /*!< PLIC Claim/Complete register offset */
|
||||
#define PLIC_THRESHOLD_SHIFT_PER_CONTEXT 12 /*!< log2(0x1000), shift per context */
|
||||
#define PLIC_CLAIM_SHIFT_PER_CONTEXT 12 /*!< log2(0x1000), shift per context */
|
||||
|
||||
#ifndef __PLIC_BASEADDR
|
||||
/* Base address of PLIC(__PLIC_BASEADDR) should be defined in <Device.h> */
|
||||
#error "__PLIC_BASEADDR is not defined, please check!"
|
||||
#endif
|
||||
|
||||
/* PLIC Memory mapping of Device */
|
||||
#define PLIC_BASE __PLIC_BASEADDR /*!< PLIC Base Address */
|
||||
|
||||
/**
|
||||
* PLIC_GetHartID() is used to get plic hartid which might not be the same as cpu hart id,
|
||||
* for example, cpu hartid may be 1, but plic hartid may be 0, then plic hartid offset is 1.
|
||||
* If defined __PLIC_HARTID, it will use __PLIC_HARTID as plic hartid,
|
||||
* otherwise, it will use __get_hart_index().
|
||||
* The cpu hartid is get by using __get_hart_id function
|
||||
*/
|
||||
#ifndef __PLIC_HARTID
|
||||
#define PLIC_GetHartID() (__get_hart_index())
|
||||
#define PLIC_GetHartID_S() (__get_hart_index_s())
|
||||
#else
|
||||
#define PLIC_GetHartID() (__PLIC_HARTID)
|
||||
#define PLIC_GetHartID_S() (__PLIC_HARTID)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Context ID mapping (Nuclei RISC-V CPU convention):
|
||||
* M-mode: ctxid = hartid * 2 (even: 0, 2, 4, 6, 8)
|
||||
* S-mode: ctxid = hartid * 2 + 1 (odd: 1, 3, 5, 7, 9)
|
||||
* This is NOT part of the RISC-V PLIC spec.
|
||||
*/
|
||||
#define PLIC_GetHartMContextID() (PLIC_GetHartID() << 1)
|
||||
// TODO SMODE HARTID need to handle, maybe use CSR shartid defined by Nuclei RISC-V CPU
|
||||
#define PLIC_GetHartSContextID() ((PLIC_GetHartID_S() << 1) + 1)
|
||||
|
||||
#define PLIC_PRIORITY_REGADDR(source) ((PLIC_BASE) + (PLIC_PRIORITY_OFFSET) + ((source) << PLIC_PRIORITY_SHIFT_PER_SOURCE))
|
||||
#define PLIC_PENDING_REGADDR(source) ((PLIC_BASE) + (PLIC_PENDING_OFFSET) + (((source) >> 5) * 4))
|
||||
#define PLIC_ENABLE_REGADDR(ctxid, source) ((PLIC_BASE) + (PLIC_ENABLE_OFFSET) + ((ctxid) << PLIC_ENABLE_SHIFT_PER_CONTEXT) + ((source) >> 5) * 4)
|
||||
#define PLIC_THRESHOLD_REGADDR(ctxid) ((PLIC_BASE) + (PLIC_THRESHOLD_OFFSET) + ((ctxid) << PLIC_THRESHOLD_SHIFT_PER_CONTEXT))
|
||||
#define PLIC_CLAIM_REGADDR(ctxid) ((PLIC_BASE) + (PLIC_CLAIM_OFFSET) + ((ctxid) << PLIC_CLAIM_SHIFT_PER_CONTEXT))
|
||||
#define PLIC_COMPLETE_REGADDR(ctxid) (PLIC_CLAIM_REGADDR(ctxid))
|
||||
|
||||
|
||||
/** @} */ /* end of group NMSIS_Core_PLIC_Registers */
|
||||
|
||||
/* ########################## PLIC functions #################################### */
|
||||
/**
|
||||
* \defgroup NMSIS_Core_IntPlic PLIC Interrupt
|
||||
* \brief Functions that manage interrupts via the PLIC.
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* \brief Set priority threshold value of plic for selected context
|
||||
* \details
|
||||
* This function set priority threshold value of plic for selected context.
|
||||
* \param [in] ctxid selected context id
|
||||
* \param [in] thresh threshold value
|
||||
* \remarks
|
||||
* \sa
|
||||
* - \ref PLIC_GetContextThreshold
|
||||
*/
|
||||
__STATIC_FORCEINLINE void PLIC_SetContextThreshold(uint32_t ctxid, uint32_t thresh)
|
||||
{
|
||||
volatile uint32_t *thresh_reg = (uint32_t *)PLIC_THRESHOLD_REGADDR(ctxid);
|
||||
|
||||
*thresh_reg = thresh;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Get priority threshold value of plic for selected context
|
||||
* \details
|
||||
* This function get priority threshold value of plic for selected context.
|
||||
* \param [in] ctxid selected context id
|
||||
* \return priority threshold value for selected context
|
||||
* \remarks
|
||||
* \sa
|
||||
* - \ref PLIC_SetContextThreshold
|
||||
*/
|
||||
__STATIC_FORCEINLINE uint32_t PLIC_GetContextThreshold(uint32_t ctxid)
|
||||
{
|
||||
volatile uint32_t *thresh_reg = (uint32_t *)PLIC_THRESHOLD_REGADDR(ctxid);
|
||||
|
||||
return (*thresh_reg);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Enable interrupt of selected source plic for selected context
|
||||
* \details
|
||||
* This function enable interrupt of selected source plic for selected context.
|
||||
* \param [in] ctxid selected context id
|
||||
* \param [in] source interrupt source
|
||||
* \remarks
|
||||
* \sa
|
||||
* - \ref PLIC_DisableContextInterrupt
|
||||
*/
|
||||
__STATIC_FORCEINLINE void PLIC_EnableContextInterrupt(uint32_t ctxid, uint32_t source)
|
||||
{
|
||||
volatile uint32_t *enable_reg = (uint32_t *)PLIC_ENABLE_REGADDR(ctxid, source);
|
||||
|
||||
uint32_t current = *enable_reg;
|
||||
current = current | (1UL << (source & 0x1F));
|
||||
*enable_reg = current;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Disable interrupt of selected source plic for selected context
|
||||
* \details
|
||||
* This function disable interrupt of selected source plic for selected context
|
||||
* \param [in] ctxid selected context id
|
||||
* \param [in] source interrupt source
|
||||
* \remarks
|
||||
* \sa
|
||||
* - \ref PLIC_EnableContextInterrupt
|
||||
*/
|
||||
__STATIC_FORCEINLINE void PLIC_DisableContextInterrupt(uint32_t ctxid, uint32_t source)
|
||||
{
|
||||
volatile uint32_t *enable_reg = (uint32_t *)PLIC_ENABLE_REGADDR(ctxid, source);
|
||||
|
||||
uint32_t current = *enable_reg;
|
||||
current = current & (~(1UL << (source & 0x1F)));
|
||||
*enable_reg = current;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Get interrupt enable status of selected source plic for selected context
|
||||
* \details
|
||||
* This function get interrupt enable of selected source plic for selected context.
|
||||
* \param [in] ctxid selected context id
|
||||
* \param [in] source interrupt source
|
||||
* \return enable status for selected interrupt source for selected context
|
||||
* \remarks
|
||||
* \sa
|
||||
* - \ref PLIC_EnableContextInterrupt
|
||||
* - \ref PLIC_DisableContextInterrupt
|
||||
*/
|
||||
__STATIC_FORCEINLINE uint32_t PLIC_GetContextInterruptEnable(uint32_t ctxid, uint32_t source)
|
||||
{
|
||||
volatile uint32_t *enable_reg = (uint32_t *)PLIC_ENABLE_REGADDR(ctxid, source);
|
||||
|
||||
uint32_t current = *enable_reg;
|
||||
current = (current >> (source & 0x1F)) & 0x1;
|
||||
return current;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Set interrupt pending of selected source plic
|
||||
* \details
|
||||
* This function set interrupt pending of selected source plic.
|
||||
* \param [in] source interrupt source
|
||||
* \remarks
|
||||
* \sa
|
||||
* - \ref PLIC_GetInterruptPending
|
||||
* - \ref PLIC_CLearInterruptPending
|
||||
*/
|
||||
__STATIC_FORCEINLINE void PLIC_SetInterruptPending(uint32_t source)
|
||||
{
|
||||
volatile uint32_t *pending_reg = (uint32_t *)PLIC_PENDING_REGADDR(source);
|
||||
|
||||
uint32_t current = *pending_reg;
|
||||
current = current | (1UL << (source & 0x1F));
|
||||
*pending_reg = current;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Clear interrupt pending of selected source plic
|
||||
* \details
|
||||
* This function clear interrupt pending of selected source plic
|
||||
* \param [in] source interrupt source
|
||||
* \remarks
|
||||
* \sa
|
||||
* - \ref PLIC_SetInterruptPending
|
||||
* - \ref PLIC_GetInterruptPending
|
||||
*/
|
||||
__STATIC_FORCEINLINE void PLIC_ClearInterruptPending(uint32_t source)
|
||||
{
|
||||
volatile uint32_t *pending_reg = (uint32_t *)PLIC_PENDING_REGADDR(source);
|
||||
|
||||
uint32_t current = *pending_reg;
|
||||
current = current & (~(1UL << (source & 0x1F)));
|
||||
*pending_reg = current;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Get interrupt pending status of selected source plic
|
||||
* \details
|
||||
* This function get interrupt pending of selected source plic
|
||||
* \param [in] source interrupt source
|
||||
* \return interrupt pending status for selected interrupt source
|
||||
* \remarks
|
||||
* \sa
|
||||
* - \ref PLIC_SetInterruptPending
|
||||
* - \ref PLIC_ClearInterruptPending
|
||||
*/
|
||||
__STATIC_FORCEINLINE uint32_t PLIC_GetInterruptPending(uint32_t source)
|
||||
{
|
||||
volatile uint32_t *pending_reg = (uint32_t *)PLIC_PENDING_REGADDR(source);
|
||||
|
||||
uint32_t current = *pending_reg;
|
||||
current = (current >> (source & 0x1F)) & 0x1;
|
||||
return current;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Set interrupt priority for selected source plic
|
||||
* \details
|
||||
* This function set interrupt priority for selected source plic.
|
||||
* \param [in] source interrupt source
|
||||
* \param [in] priority interrupt priority
|
||||
* \remarks
|
||||
* \sa
|
||||
* - \ref PLIC_GetPriority
|
||||
*/
|
||||
__STATIC_FORCEINLINE void PLIC_SetPriority(uint32_t source, uint32_t priority)
|
||||
{
|
||||
volatile uint32_t *priority_reg = (uint32_t *)PLIC_PRIORITY_REGADDR(source);
|
||||
|
||||
*priority_reg = priority;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Get interrupt priority for selected source plic
|
||||
* \details
|
||||
* This function get interrupt priority for selected source plic.
|
||||
* \param [in] source interrupt source
|
||||
* \param [in] priority interrupt priority
|
||||
* \remarks
|
||||
* \sa
|
||||
* - \ref PLIC_SetPriority
|
||||
*/
|
||||
__STATIC_FORCEINLINE uint32_t PLIC_GetPriority(uint32_t source)
|
||||
{
|
||||
volatile uint32_t *priority_reg = (uint32_t *)PLIC_PRIORITY_REGADDR(source);
|
||||
|
||||
return (*priority_reg);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Claim interrupt for plic for selected context
|
||||
* \details
|
||||
* This function claim interrupt for plic for selected context.
|
||||
* \param [in] ctxid selected context id
|
||||
* \return the ID of the highest priority pending interrupt or
|
||||
* zero if there is no pending interrupt
|
||||
* \remarks
|
||||
* A successful claim will also atomically clear the corresponding pending bit
|
||||
* on the interrupt source. The PLIC can perform a claim at any time and the
|
||||
* claim operation is not affected by the setting of the priority threshold register.
|
||||
* \sa
|
||||
* - \ref PLIC_CompleteContextInterrupt
|
||||
*/
|
||||
__STATIC_FORCEINLINE uint32_t PLIC_ClaimContextInterrupt(uint32_t ctxid)
|
||||
{
|
||||
volatile uint32_t *claim_reg = (uint32_t *)PLIC_CLAIM_REGADDR(ctxid);
|
||||
|
||||
return (*claim_reg);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Complete interrupt for plic for selected context
|
||||
* \details
|
||||
* This function complete interrupt for plic for selected context.
|
||||
* \param [in] ctxid selected context id
|
||||
* \param [in] source interrupt source ID to complete
|
||||
* \remarks
|
||||
* The PLIC signals it has completed executing an interrupt handler by writing
|
||||
* the interrupt ID it received from the claim to the claim/complete register.
|
||||
* The PLIC does not check whether the completion ID is the same as the last
|
||||
* claim ID for that context.
|
||||
* If the completion ID does not match an interrupt source that is currently
|
||||
* enabled for the context, the completion is silently ignored.
|
||||
* \sa
|
||||
* - \ref PLIC_ClaimContextInterrupt
|
||||
*/
|
||||
__STATIC_FORCEINLINE void PLIC_CompleteContextInterrupt(uint32_t ctxid, uint32_t source)
|
||||
{
|
||||
volatile uint32_t *complete_reg = (uint32_t *)PLIC_COMPLETE_REGADDR(ctxid);
|
||||
|
||||
*complete_reg = source;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Perform init for plic for selected context
|
||||
* \details
|
||||
* This function perform initialization steps for plic for selected context.
|
||||
* \param [in] ctxid selected context id
|
||||
* \param [in] num_sources plic interrupt source count number
|
||||
* \param [in] enable plic interrupt enable or not
|
||||
* \param [in] thresh plic interrupt threshold
|
||||
* \remarks
|
||||
* * Disable all interrupts
|
||||
* * Set priority threshold to value specified by thresh
|
||||
*/
|
||||
__STATIC_INLINE void PLIC_Context_Init(uint32_t ctxid, uint32_t num_sources, uint32_t enable, uint32_t thresh)
|
||||
{
|
||||
uint32_t i;
|
||||
|
||||
for (i = 0; i < num_sources; i ++) {
|
||||
if (enable) {
|
||||
PLIC_EnableContextInterrupt(ctxid, i);
|
||||
} else {
|
||||
PLIC_DisableContextInterrupt(ctxid, i);
|
||||
}
|
||||
}
|
||||
PLIC_SetContextThreshold(ctxid, thresh);
|
||||
}
|
||||
|
||||
#define PLIC_Init(num_sources, enable, thresh) PLIC_Context_Init(PLIC_GetHartMContextID(), (num_sources), (enable), (thresh))
|
||||
#define PLIC_Init_S(num_sources, enable, thresh) PLIC_Context_Init(PLIC_GetHartSContextID(), (num_sources), (enable), (thresh))
|
||||
|
||||
#define PLIC_ClaimInterrupt() PLIC_ClaimContextInterrupt(PLIC_GetHartMContextID())
|
||||
#define PLIC_ClaimInterrupt_S() PLIC_ClaimContextInterrupt(PLIC_GetHartSContextID())
|
||||
|
||||
#define PLIC_CompleteInterrupt(source) PLIC_CompleteContextInterrupt(PLIC_GetHartMContextID(), (source))
|
||||
#define PLIC_CompleteInterrupt_S(source) PLIC_CompleteContextInterrupt(PLIC_GetHartSContextID(), (source))
|
||||
|
||||
#define PLIC_GetInterruptEnable(source) PLIC_GetContextInterruptEnable(PLIC_GetHartMContextID(), (source))
|
||||
#define PLIC_GetInterruptEnable_S(source) PLIC_GetContextInterruptEnable(PLIC_GetHartSContextID(), (source))
|
||||
|
||||
#define PLIC_EnableInterrupt(source) PLIC_EnableContextInterrupt(PLIC_GetHartMContextID(), (source))
|
||||
#define PLIC_EnableInterrupt_S(source) PLIC_EnableContextInterrupt(PLIC_GetHartSContextID(), (source))
|
||||
|
||||
#define PLIC_DisableInterrupt(source) PLIC_DisableContextInterrupt(PLIC_GetHartMContextID(), (source))
|
||||
#define PLIC_DisableInterrupt_S(source) PLIC_DisableContextInterrupt(PLIC_GetHartSContextID(), (source))
|
||||
|
||||
#define PLIC_SetThreshold(thresh) PLIC_SetContextThreshold(PLIC_GetHartMContextID(), (thresh))
|
||||
#define PLIC_SetThreshold_S(thresh) PLIC_SetContextThreshold(PLIC_GetHartSContextID(), (thresh))
|
||||
|
||||
#define PLIC_GetThreshold() PLIC_GetContextThreshold(PLIC_GetHartMContextID())
|
||||
#define PLIC_GetThreshold_S() PLIC_GetContextThreshold(PLIC_GetHartSContextID())
|
||||
|
||||
/**
|
||||
* \brief Set Trap entry address
|
||||
* \details
|
||||
* This function set trap entry address to 'CSR_MTVEC'.
|
||||
* \param [in] addr trap entry address
|
||||
* \remarks
|
||||
* - This function use to set trap entry address to 'CSR_MTVEC'.
|
||||
* \sa
|
||||
* - \ref __get_trap_entry
|
||||
*/
|
||||
__STATIC_FORCEINLINE void __set_trap_entry(rv_csr_t addr)
|
||||
{
|
||||
addr &= (rv_csr_t)(~0x7);
|
||||
__RV_CSR_WRITE(CSR_MTVEC, addr);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Get trap entry address
|
||||
* \details
|
||||
* This function get trap entry address from 'CSR_MTVEC'.
|
||||
* \return trap entry address
|
||||
* \remarks
|
||||
* - This function use to get trap entry address from 'CSR_MTVEC'.
|
||||
* \sa
|
||||
* - \ref __set_trap_entry
|
||||
*/
|
||||
__STATIC_FORCEINLINE rv_csr_t __get_trap_entry(void)
|
||||
{
|
||||
unsigned long addr = __RV_CSR_READ(CSR_MTVEC);
|
||||
return (addr);
|
||||
}
|
||||
|
||||
/** @} */ /* End of Doxygen Group NMSIS_Core_IntExc */
|
||||
|
||||
#endif /* defined(__PLIC_PRESENT) && (__PLIC_PRESENT == 1) */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif /** __CORE_FEATURE_PLIC__ */
|
||||
@@ -0,0 +1,362 @@
|
||||
/*
|
||||
* Copyright (c) 2019 Nuclei Limited. All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* 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 __CORE_FEATURE_PMA_H__
|
||||
#define __CORE_FEATURE_PMA_H__
|
||||
/*!
|
||||
* @file core_feature_pma.h
|
||||
* @brief Physical memory attribute feature API header file
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "core_compatiable.h"
|
||||
|
||||
#if defined(__PMA_PRESENT) && (__PMA_PRESENT==1)
|
||||
|
||||
/* ===== PMA functions ===== */
|
||||
/**
|
||||
* \defgroup NMSIS_Core_PMA_Functions PMA Functions
|
||||
* \ingroup NMSIS_Core
|
||||
* \brief Functions that set/disable/enable different attribute type(Device/Non-Cacheable/Cacheable) memory regions, or get region info.
|
||||
* \details
|
||||
* Nuclei provide Physical Memory Attribute(PMA) to define the attribute of memory.PMA will affect CPU access memory behavior.
|
||||
*
|
||||
* PMA are split into three attributes:
|
||||
* * Device(abbreviated as 'DEV') Attribute
|
||||
* * Non-Cacheable(abbreviated as 'NC') Attribute
|
||||
* * Cacheable(abbreviated as 'CA') Attribute
|
||||
* And correspondingly, the whole memory region are split into three regions: DEV Region/NC Region/CA Region
|
||||
*
|
||||
* Hardware provide some software CSR to set the pma by mattri(n)_base/mattri(n)_mask/sattri(n)_base/sattri(n)_mask
|
||||
*
|
||||
* Hardware defined PMA regions(up to 8 DEV/NC/CA regions) can be disable or enable by CSR mmacro_dev_en/mmacro_noc_en/mmacro_ca_en
|
||||
* @{
|
||||
*/
|
||||
|
||||
#define PMA_REGION_TYPE_SECSHARE (1UL << 3) /*!< Set this region shareable between secure world and non-secure world, or else default is invalid */
|
||||
#define PMA_REGION_TYPE_NC (1UL << 2) /*!< Set this region Non-Cacheable, or else default is invalid */
|
||||
#define PMA_REGION_TYPE_DEV (1UL << 1) /*!< Set this region Device, or else default is invalid */
|
||||
#define PMA_REGION_TYPE_CA (0) /*!< Set this region Cacheable, which is default */
|
||||
#define PMA_REGION_ENA (1UL << 0) /*!< Enable this region, then the region type will take effect */
|
||||
#define PMA_REGION_DIS (0) /*!< Disable this region */
|
||||
|
||||
typedef struct PMA_CONFIG {
|
||||
/**
|
||||
* Base physical address, which needs to be 4K byte aligned
|
||||
*/
|
||||
unsigned long region_base;
|
||||
/**
|
||||
* Region size, which needs to be 4K byte aligned; the \ref region_base should be aligined by \ref region_size
|
||||
*/
|
||||
unsigned long region_size;
|
||||
/**
|
||||
* Type could be \ref PMA_REGION_TYPE_SECSHARE, \ref PMA_REGION_TYPE_NC, \ref PMA_REGION_TYPE_DEV, \ref PMA_REGION_TYPE_CA
|
||||
* \ref PMA_REGION_TYPE_SECSHARE could be combined with one of \ref PMA_REGION_TYPE_NC \ref PMA_REGION_TYPE_DEV \ref PMA_REGION_TYPE_CA
|
||||
* such as \ref PMA_REGION_TYPE_SECSHARE | \ref PMA_REGION_TYPE_NC
|
||||
* Reserved for sattri(n)_base
|
||||
*/
|
||||
uint16_t region_type;
|
||||
/**
|
||||
* Enable or disable the region, could be \ref PMA_REGION_ENA, \ref PMA_REGION_DIS
|
||||
*/
|
||||
uint16_t region_enable;
|
||||
} pma_config;
|
||||
|
||||
/**
|
||||
* \brief Configure one region in machine mode
|
||||
* \details Set the region(0-n) info of base address/region type/region size/enable status
|
||||
* \param [in] entry_idx Index(0-n) of paired mattri(n)_mask and mattri(n)_base
|
||||
* \param [in] pma_cfg Region info to configure
|
||||
* \return -1 failure, else 0 success
|
||||
* \remarks
|
||||
* - The entry_idx(0-n) depends on number of paired mattri(n)_mask and mattri(n)_base, refer to
|
||||
Nuclei ISA specifications
|
||||
* - Not all the entry_idx(0-n) could set to all the types freely, refer to Nuclei ISA specifications
|
||||
* - The mattri(n)_mask must be written first, before mattri(n)_base, which the api takes care of.
|
||||
* - The higher bits of mattri(n)_mask should be continuously 1, the remaining lower bits should be all 0
|
||||
* and the number (N) of 0 means the size of this region(2^N bytes)
|
||||
* - Region granularity is 4KB, so the low 12-bits of mattri(n)_mask must be 0, which the api takes care of
|
||||
* - The regions can be overlapped as the prority: Non-Cacheable > Cacheable > Device, but especially be careful not to
|
||||
* overlap software's instruction/data sections by Device, or overlap Device(like uart) memory by Cacheable
|
||||
*/
|
||||
__STATIC_INLINE long PMA_SetRegion(unsigned long entry_idx, pma_config *pma_cfg)
|
||||
{
|
||||
// 4KB aligned
|
||||
unsigned long size = (pma_cfg->region_size >> 12) << 12;
|
||||
unsigned long base_addr = (pma_cfg->region_base >> 12) << 12;
|
||||
|
||||
if ((entry_idx + 1) > __PMA_CSR_NUM) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
rv_csr_t mask = (unsigned long)(~(size - 1));
|
||||
rv_csr_t base = pma_cfg->region_type | base_addr | pma_cfg->region_enable;
|
||||
|
||||
switch (entry_idx) {
|
||||
// Bit[MXLEN-1:PA_SIZE] of mattri(n)_mask is reserved 0
|
||||
case 0: __RV_CSR_WRITE(CSR_MATTRI0_BASE, 0); __RV_CSR_WRITE(CSR_MATTRI0_MASK, mask); __RV_CSR_WRITE(CSR_MATTRI0_BASE, base); break;
|
||||
case 1: __RV_CSR_WRITE(CSR_MATTRI1_BASE, 0); __RV_CSR_WRITE(CSR_MATTRI1_MASK, mask); __RV_CSR_WRITE(CSR_MATTRI1_BASE, base); break;
|
||||
case 2: __RV_CSR_WRITE(CSR_MATTRI2_BASE, 0); __RV_CSR_WRITE(CSR_MATTRI2_MASK, mask); __RV_CSR_WRITE(CSR_MATTRI2_BASE, base); break;
|
||||
case 3: __RV_CSR_WRITE(CSR_MATTRI3_BASE, 0); __RV_CSR_WRITE(CSR_MATTRI3_MASK, mask); __RV_CSR_WRITE(CSR_MATTRI3_BASE, base); break;
|
||||
case 4: __RV_CSR_WRITE(CSR_MATTRI4_BASE, 0); __RV_CSR_WRITE(CSR_MATTRI4_MASK, mask); __RV_CSR_WRITE(CSR_MATTRI4_BASE, base); break;
|
||||
case 5: __RV_CSR_WRITE(CSR_MATTRI5_BASE, 0); __RV_CSR_WRITE(CSR_MATTRI5_MASK, mask); __RV_CSR_WRITE(CSR_MATTRI5_BASE, base); break;
|
||||
case 6: __RV_CSR_WRITE(CSR_MATTRI6_BASE, 0); __RV_CSR_WRITE(CSR_MATTRI6_MASK, mask); __RV_CSR_WRITE(CSR_MATTRI6_BASE, base); break;
|
||||
case 7: __RV_CSR_WRITE(CSR_MATTRI7_BASE, 0); __RV_CSR_WRITE(CSR_MATTRI7_MASK, mask); __RV_CSR_WRITE(CSR_MATTRI7_BASE, base); break;
|
||||
default: return -1;
|
||||
}
|
||||
__FENCE_I();
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Get the region info in machine mode
|
||||
* \details Read the region(0-n) info of base address/region type/region size/enable status
|
||||
* \param [in] entry_idx Index(0-n) of paired mattri(n)_mask and mattri(n)_base
|
||||
* \param [out] pma_cfg Region info read
|
||||
* \return 0 if success, else -1
|
||||
* \remarks
|
||||
* - entry_idx(0-n) depends on number of paired mattri(n)_mask and mattri(n)_base, refer to
|
||||
Nuclei ISA specifications
|
||||
* - Not all the entry_idx(0-n) could set to all the types freely, refer to Nuclei ISA specifications
|
||||
*/
|
||||
__STATIC_INLINE long PMA_GetRegion(unsigned long entry_idx, pma_config *pma_cfg)
|
||||
{
|
||||
rv_csr_t mask, base;
|
||||
uint32_t mpasize = *(uint32_t *)__IINFO_MPASIZE_ADDR;
|
||||
|
||||
if ((entry_idx + 1) > __PMA_CSR_NUM) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
switch (entry_idx) {
|
||||
case 0: mask = __RV_CSR_READ(CSR_MATTRI0_MASK); base = __RV_CSR_READ(CSR_MATTRI0_BASE); break;
|
||||
case 1: mask = __RV_CSR_READ(CSR_MATTRI1_MASK); base = __RV_CSR_READ(CSR_MATTRI1_BASE); break;
|
||||
case 2: mask = __RV_CSR_READ(CSR_MATTRI2_MASK); base = __RV_CSR_READ(CSR_MATTRI2_BASE); break;
|
||||
case 3: mask = __RV_CSR_READ(CSR_MATTRI3_MASK); base = __RV_CSR_READ(CSR_MATTRI3_BASE); break;
|
||||
case 4: mask = __RV_CSR_READ(CSR_MATTRI4_MASK); base = __RV_CSR_READ(CSR_MATTRI4_BASE); break;
|
||||
case 5: mask = __RV_CSR_READ(CSR_MATTRI5_MASK); base = __RV_CSR_READ(CSR_MATTRI5_BASE); break;
|
||||
case 6: mask = __RV_CSR_READ(CSR_MATTRI6_MASK); base = __RV_CSR_READ(CSR_MATTRI6_BASE); break;
|
||||
case 7: mask = __RV_CSR_READ(CSR_MATTRI7_MASK); base = __RV_CSR_READ(CSR_MATTRI7_BASE); break;
|
||||
default: return -1;
|
||||
}
|
||||
|
||||
pma_cfg->region_type = (unsigned long)(base & 0x0E);
|
||||
pma_cfg->region_base = (unsigned long)((base >> 12) << 12);
|
||||
pma_cfg->region_size = (unsigned long)(1UL << (mask == 0 ? mpasize : __CTZ(mask)));
|
||||
pma_cfg->region_enable = (uint16_t)(base & 0x01);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Configure one region for Secure S-Mode world to share with Non-Secure S-Mode world
|
||||
* \details Set the region(0-7) info of base address/region size/enable status
|
||||
* \param [in] entry_idx Index(0-7) of paired sattri(n)_mask and sattri(n)_base
|
||||
* \param [in] pma_cfg Region info to configure
|
||||
* \return 0 if success, else -1
|
||||
* \remarks
|
||||
* - sattri(n)_mask must be written first, before sattri(n)_base, which the api takes care of
|
||||
* - The higher bits of sattri(n)_mask should be continuously 1, the remaining lower bits should be all 0
|
||||
* and the number (N) of 0 means the size of this region(2^N bytes)
|
||||
* - Region granularity is 4KB, so the low 12-bits of sattri(n)_mask must be 0, which the api takes care of
|
||||
* - Unlike mattri(n)_base, there's no DEV Region/NC Region/CA Region type
|
||||
*/
|
||||
__STATIC_INLINE long PMA_SetRegion_S(unsigned long entry_idx, pma_config *pma_cfg)
|
||||
{
|
||||
// 4KB aligned
|
||||
unsigned long size = (pma_cfg->region_size >> 12) << 12;
|
||||
unsigned long base_addr = (pma_cfg->region_base >> 12) << 12;
|
||||
|
||||
if ((entry_idx + 1) > __PMA_SEC_CSR_NUM) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
rv_csr_t mask = (unsigned long)(~(size - 1));
|
||||
rv_csr_t base = base_addr | pma_cfg->region_enable;
|
||||
|
||||
switch (entry_idx) {
|
||||
// Bit[MXLEN-1:PA_SIZE] of sattri(n)_mask is reserved 0
|
||||
case 0: __RV_CSR_WRITE(CSR_SATTRI0_MASK, mask); __RV_CSR_WRITE(CSR_SATTRI0_BASE, base); break;
|
||||
case 1: __RV_CSR_WRITE(CSR_SATTRI1_MASK, mask); __RV_CSR_WRITE(CSR_SATTRI1_BASE, base); break;
|
||||
case 2: __RV_CSR_WRITE(CSR_SATTRI2_MASK, mask); __RV_CSR_WRITE(CSR_SATTRI2_BASE, base); break;
|
||||
case 3: __RV_CSR_WRITE(CSR_SATTRI3_MASK, mask); __RV_CSR_WRITE(CSR_SATTRI3_BASE, base); break;
|
||||
case 4: __RV_CSR_WRITE(CSR_SATTRI4_MASK, mask); __RV_CSR_WRITE(CSR_SATTRI4_BASE, base); break;
|
||||
case 5: __RV_CSR_WRITE(CSR_SATTRI5_MASK, mask); __RV_CSR_WRITE(CSR_SATTRI5_BASE, base); break;
|
||||
case 6: __RV_CSR_WRITE(CSR_SATTRI6_MASK, mask); __RV_CSR_WRITE(CSR_SATTRI6_BASE, base); break;
|
||||
case 7: __RV_CSR_WRITE(CSR_SATTRI7_MASK, mask); __RV_CSR_WRITE(CSR_SATTRI7_BASE, base); break;
|
||||
default: return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Get the region info of Secure S-Mode world sharing with Non-Secure S-Mode world
|
||||
* \details Read the region(0-7) info of base address/region size/enable status
|
||||
* \param [in] entry_idx Index(0-7) of paired sattri(n)_mask and sattri(n)_base
|
||||
* \param [out] pma_cfg Region info read
|
||||
* \return 0 if success, else -1
|
||||
* \remark
|
||||
* - Unlike mattri(n)_base, there's no DEV Region/NC Region/CA Region type
|
||||
*/
|
||||
__STATIC_INLINE long PMA_GetRegion_S(unsigned long entry_idx, pma_config *pma_cfg)
|
||||
{
|
||||
rv_csr_t mask, base;
|
||||
uint32_t mpasize = *(uint32_t *)__IINFO_MPASIZE_ADDR;
|
||||
|
||||
if ((entry_idx + 1) > __PMA_SEC_CSR_NUM) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
switch (entry_idx) {
|
||||
case 0: mask = __RV_CSR_READ(CSR_SATTRI0_MASK); base = __RV_CSR_READ(CSR_SATTRI0_BASE); break;
|
||||
case 1: mask = __RV_CSR_READ(CSR_SATTRI1_MASK); base = __RV_CSR_READ(CSR_SATTRI1_BASE); break;
|
||||
case 2: mask = __RV_CSR_READ(CSR_SATTRI2_MASK); base = __RV_CSR_READ(CSR_SATTRI2_BASE); break;
|
||||
case 3: mask = __RV_CSR_READ(CSR_SATTRI3_MASK); base = __RV_CSR_READ(CSR_SATTRI3_BASE); break;
|
||||
case 4: mask = __RV_CSR_READ(CSR_SATTRI4_MASK); base = __RV_CSR_READ(CSR_SATTRI4_BASE); break;
|
||||
case 5: mask = __RV_CSR_READ(CSR_SATTRI5_MASK); base = __RV_CSR_READ(CSR_SATTRI5_BASE); break;
|
||||
case 6: mask = __RV_CSR_READ(CSR_SATTRI6_MASK); base = __RV_CSR_READ(CSR_SATTRI6_BASE); break;
|
||||
case 7: mask = __RV_CSR_READ(CSR_SATTRI7_MASK); base = __RV_CSR_READ(CSR_SATTRI7_BASE); break;
|
||||
default: return -1;
|
||||
}
|
||||
|
||||
pma_cfg->region_base = (unsigned long)((base >> 12) << 12);
|
||||
pma_cfg->region_size = (unsigned long)(1UL << (mask == 0 ? mpasize : __CTZ(mask)));
|
||||
pma_cfg->region_enable = (uint16_t)(base & 0x01);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if defined(__PMA_MACRO_PRESENT) && (__PMA_MACRO_PRESENT == 1)
|
||||
/**
|
||||
* \brief Enable hardware defined Device regions
|
||||
* \details Enable Device region by corresponding index
|
||||
* \param [in] entry_idx Index(0-7)
|
||||
* \remarks
|
||||
* - This function can be called in M-Mode only.
|
||||
* - When there is no entry_idx, this field is tied to 0
|
||||
* - For each region entry's address/size/attribute detail refers to RTL Configuration Stage
|
||||
* - The regions can be overlapped as the prority: Non-Cacheable > Cacheable > Device, but especially be careful not to
|
||||
* overlap software's instruction/data sections by Device, or overlap Device(like uart) memory by Cacheable
|
||||
* \sa
|
||||
* - \ref PMA_DisableHwDevRegion
|
||||
*/
|
||||
__STATIC_FORCEINLINE void PMA_EnableHwDevRegion(unsigned long entry_idx)
|
||||
{
|
||||
__RV_CSR_SET(CSR_MMACRO_DEV_EN, 1UL << entry_idx);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Disable hardware defined Device regions
|
||||
* \details Disable Device region by corresponding index
|
||||
* \param [in] entry_idx Index(0-7)
|
||||
* \remarks
|
||||
* - This function can be called in M-Mode only.
|
||||
* - When there is no entry_idx, this field is tied to 0
|
||||
* - For each region entry's address/size/attribute detail refers to RTL Configuration Stage
|
||||
* - The regions can be overlapped as the prority: Non-Cacheable > Cacheable > Device, but especially be careful not to
|
||||
* overlap software's instruction/data sections by Device, or overlap Device(like uart) memory by Cacheable
|
||||
* \sa
|
||||
* - \ref PMA_EnableHwDevRegion
|
||||
*/
|
||||
__STATIC_FORCEINLINE void PMA_DisableHwDevRegion(unsigned long entry_idx)
|
||||
{
|
||||
__RV_CSR_CLEAR(CSR_MMACRO_DEV_EN, 1UL << entry_idx);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Enable hardware defined Non-Cacheable regions
|
||||
* \details Enable Non-Cacheable region by corresponding index
|
||||
* \param [in] entry_idx Index(0-7)
|
||||
* \remarks
|
||||
* - This function can be called in M-Mode only.
|
||||
* - When there is no entry_idx, this field is tied to 0
|
||||
* - For each region entry's address/size/attribute detail refers to RTL Configuration Stage
|
||||
* - The regions can be overlapped as the prority: Non-Cacheable > Cacheable > Device, but especially be careful not to
|
||||
* overlap software's instruction/data sections by Device, or overlap Device(like uart) memory by Cacheable
|
||||
* \sa
|
||||
* - \ref PMA_DisableHwNCRegion
|
||||
*/
|
||||
__STATIC_FORCEINLINE void PMA_EnableHwNCRegion(unsigned long entry_idx)
|
||||
{
|
||||
__RV_CSR_SET(CSR_MMACRO_NOC_EN, 1UL << entry_idx);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Disable hardware defined Non-Cacheable regions
|
||||
* \details Disable Non-Cacheable region by corresponding index
|
||||
* \param [in] entry_idx Index(0-7)
|
||||
* \remarks
|
||||
* - This function can be called in M-Mode only.
|
||||
* - When there is no entry_idx, this field is tied to 0
|
||||
* - For each region entry's address/size/attribute detail refers to RTL Configuration Stage
|
||||
* - The regions can be overlapped as the prority: Non-Cacheable > Cacheable > Device, but especially be careful not to
|
||||
* overlap software's instruction/data sections by Device, or overlap Device(like uart) memory by Cacheable
|
||||
* \sa
|
||||
* - \ref PMA_EnableHwNCRegion
|
||||
*/
|
||||
__STATIC_FORCEINLINE void PMA_DisableHwNCRegion(unsigned long entry_idx)
|
||||
{
|
||||
__RV_CSR_CLEAR(CSR_MMACRO_NOC_EN, 1UL << entry_idx);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Enable hardware defined Cacheable regions
|
||||
* \details Enable Cacheable region by corresponding index
|
||||
* \param [in] entry_idx Index(0-7)
|
||||
* \remarks
|
||||
* - This function can be called in M-Mode only.
|
||||
* - When there is no entry_idx, this field is tied to 0
|
||||
* - For each region entry's address/size/attribute detail refers to RTL Configuration Stage
|
||||
* - The regions can be overlapped as the prority: Non-Cacheable > Cacheable > Device, but especially be careful not to
|
||||
* overlap software's instruction/data sections by Device, or overlap Device(like uart) memory by Cacheable
|
||||
* \sa
|
||||
* - \ref PMA_DisableHwCARegion
|
||||
*/
|
||||
__STATIC_FORCEINLINE void PMA_EnableHwCARegion(unsigned long entry_idx)
|
||||
{
|
||||
__RV_CSR_SET(CSR_MMACRO_CA_EN, 1UL << entry_idx);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Disable hardware defined Cacheable regions
|
||||
* \details Disable Cacheable region by corresponding index
|
||||
* \param [in] entry_idx Index(0-7)
|
||||
* \remarks
|
||||
* - This function can be called in M-Mode only.
|
||||
* - When there is no entry_idx, this field is tied to 0
|
||||
* - For each region entry's address/size/attribute detail refers to RTL Configuration Stage
|
||||
* - The regions can be overlapped as the prority: Non-Cacheable > Cacheable > Device, but especially be careful not to
|
||||
* overlap software's instruction/data sections by Device, or overlap Device(like uart) memory by Cacheable
|
||||
* \sa
|
||||
* - \ref PMA_EnableHwCARegion
|
||||
*/
|
||||
__STATIC_FORCEINLINE void PMA_DisableHwCARegion(unsigned long entry_idx)
|
||||
{
|
||||
__RV_CSR_CLEAR(CSR_MMACRO_CA_EN, 1UL << entry_idx);
|
||||
}
|
||||
#endif /* defined(__PMA_MACRO_PRESENT) && (__PMA_MACRO_PRESENT == 1) */
|
||||
/** @} */ /* End of Doxygen Group NMSIS_Core_PMA_Functions */
|
||||
#endif /* defined(__PMA_PRESENT) && (__PMA_PRESENT==1) */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif /* __CORE_FEATURE_PMA_H__ */
|
||||
@@ -0,0 +1,492 @@
|
||||
/*
|
||||
* Copyright (c) 2019 Nuclei Limited. All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* 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 __CORE_FEATURE_PMP_H__
|
||||
#define __CORE_FEATURE_PMP_H__
|
||||
/*!
|
||||
* @file core_feature_pmp.h
|
||||
* @brief PMP feature API header file for Nuclei N/NX Core
|
||||
*/
|
||||
/*
|
||||
* PMP Feature Configuration Macro:
|
||||
* 1. __PMP_PRESENT: Define whether Physical Memory Protection(PMP) is present or not
|
||||
* * 0: Not present
|
||||
* * 1: Present
|
||||
* 2. __PMP_ENTRY_NUM: Define the number of PMP entries, only 8 or 16 is configurable.
|
||||
*/
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "core_feature_base.h"
|
||||
#include "core_compatiable.h"
|
||||
|
||||
#if defined(__PMP_PRESENT) && (__PMP_PRESENT == 1)
|
||||
/* ===== PMP Operations ===== */
|
||||
/**
|
||||
* \defgroup NMSIS_Core_PMP_Functions PMP Functions
|
||||
* \ingroup NMSIS_Core
|
||||
* \brief Functions that related to the RISCV Phyiscal Memory Protection.
|
||||
* \details
|
||||
* Optional physical memory protection (PMP) unit provides per-hart machine-mode
|
||||
* control registers to allow physical memory access privileges (read, write, execute)
|
||||
* to be specified for each physical memory region.
|
||||
*
|
||||
* The PMP can supports region access control settings as small as four bytes.
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
#ifndef __PMP_ENTRY_NUM
|
||||
/* numbers of PMP entries(__PMP_ENTRY_NUM) should be defined in <Device.h> */
|
||||
#error "__PMP_ENTRY_NUM is not defined, please check!"
|
||||
#endif
|
||||
|
||||
typedef struct PMP_CONFIG {
|
||||
/**
|
||||
* set locking bit, addressing mode, read, write, and instruction execution permissions,
|
||||
* see \ref PMP_L, \ref PMP_R, \ref PMP_W, \ref PMP_X, .etc in <riscv_encoding.h>
|
||||
*/
|
||||
unsigned int protection;
|
||||
/**
|
||||
* Size of memory region as power of 2, it has to be minimum 2 and maxium \ref __RISCV_XLEN according to the
|
||||
* hard-wired granularity 2^N bytes, if N = 12, then order has to be at least 12; if not, the order read out
|
||||
* is N though you configure less than N. Generally, Nuclei CPU's pmp granularity is 2^12 = 4KBytes, you should refer to the databook.
|
||||
*/
|
||||
unsigned long order;
|
||||
/**
|
||||
* Base address of memory region
|
||||
* It must be 2^order aligned address
|
||||
*/
|
||||
unsigned long base_addr;
|
||||
} pmp_config;
|
||||
|
||||
/**
|
||||
* @brief PMPCFG list for RV32 (indices 0-7)
|
||||
*
|
||||
* For RV32, each PMPCFG register holds 4 PMP entries.
|
||||
* This list covers the first 32 entries (registers 0-7).
|
||||
*/
|
||||
#define PMPCFG_LIST_RV32_0_7 \
|
||||
X(0) X(1) X(2) X(3) X(4) X(5) X(6) X(7)
|
||||
|
||||
/**
|
||||
* @brief PMPCFG list for RV32 (indices 8-15)
|
||||
*
|
||||
* For RV32, each PMPCFG register holds 4 PMP entries.
|
||||
* This list covers entries 33-64 (registers 8-15).
|
||||
*/
|
||||
#define PMPCFG_LIST_RV32_8_15 \
|
||||
X(8) X(9) X(10) X(11) X(12) X(13) X(14) X(15)
|
||||
|
||||
/**
|
||||
* @brief PMPCFG list for RV64 (even indices 0-6)
|
||||
*
|
||||
* For RV64, each PMPCFG register holds 8 PMP entries.
|
||||
* This list covers the first 32 entries (registers 0,2,4,6).
|
||||
*/
|
||||
#define PMPCFG_LIST_RV64_0_6 \
|
||||
X(0) X(2) X(4) X(6)
|
||||
|
||||
/**
|
||||
* @brief PMPCFG list for RV64 (even indices 8-14)
|
||||
*
|
||||
* For RV64, each PMPCFG register holds 8 PMP entries.
|
||||
* This list covers entries 33-64 (registers 8,10,12,14).
|
||||
*/
|
||||
#define PMPCFG_LIST_RV64_8_14 \
|
||||
X(8) X(10) X(12) X(14)
|
||||
|
||||
/**
|
||||
* @brief Select appropriate PMPCFG list based on architecture and PMP entry count
|
||||
*
|
||||
* This macro defines the complete PMPCFG list according to:
|
||||
* - RISC-V architecture (RV32/RV64)
|
||||
* - Number of PMP entries (__PMP_ENTRY_NUM)
|
||||
*
|
||||
* @note Valid indices depend on configuration:
|
||||
* - RV32:
|
||||
* - <=32 entries: indices 0-7
|
||||
* - <=64 entries: indices 0-15
|
||||
* - RV64:
|
||||
* - <=32 entries: indices 0,2,4,6
|
||||
* - <=64 entries: indices 0,2,4,6,8,10,12,14
|
||||
*/
|
||||
#if __RISCV_XLEN == 32
|
||||
#if __PMP_ENTRY_NUM <= 32
|
||||
#define PMPCFG_LIST PMPCFG_LIST_RV32_0_7
|
||||
#elif __PMP_ENTRY_NUM <= 64
|
||||
#define PMPCFG_LIST PMPCFG_LIST_RV32_0_7 PMPCFG_LIST_RV32_8_15
|
||||
#else
|
||||
#error "Unsupported PMP_ENTRY_NUM value for RV32"
|
||||
#endif
|
||||
#elif __RISCV_XLEN == 64
|
||||
#if __PMP_ENTRY_NUM <= 32
|
||||
#define PMPCFG_LIST PMPCFG_LIST_RV64_0_6
|
||||
#elif __PMP_ENTRY_NUM <= 64
|
||||
#define PMPCFG_LIST PMPCFG_LIST_RV64_0_6 PMPCFG_LIST_RV64_8_14
|
||||
#else
|
||||
#error "Unsupported PMP_ENTRY_NUM value for RV64"
|
||||
#endif
|
||||
#else
|
||||
#error "Unsupported RISC-V architecture"
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Get PMPCFGx Register by CSR index
|
||||
* @details Return the content of the PMPCFGx Register.
|
||||
* @param [in] csr_idx PMPCFG CSR index (0-15 for RV32, 0,2,4,6,8,10,12,14 for RV64)
|
||||
* @return PMPCFGx Register value
|
||||
*
|
||||
* @note Architecture-specific behavior:
|
||||
* - RV32:
|
||||
* - Each register holds 4 PMP entries
|
||||
* - Valid indices: 0 to ceil(__PMP_ENTRY_NUM/4)-1
|
||||
* - 64 entries require indices 0-15
|
||||
* - RV64:
|
||||
* - Each register holds 8 PMP entries
|
||||
* - Only even indices are valid
|
||||
* - 64 entries require indices 0,2,4,6,8,10,12,14
|
||||
*
|
||||
* @remark The function returns 0 for invalid indices to prevent illegal accesses.
|
||||
*/
|
||||
__STATIC_INLINE rv_csr_t __get_PMPCFGx(uint32_t csr_idx)
|
||||
{
|
||||
switch (csr_idx) {
|
||||
#define X(n) case n: return __RV_CSR_READ(CSR_PMPCFG##n);
|
||||
PMPCFG_LIST
|
||||
#undef X
|
||||
default: return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set PMPCFGx by CSR index
|
||||
* @details Write the given value to the PMPCFGx Register.
|
||||
* @param [in] csr_idx PMPCFG CSR index (0-15 for RV32, 0,2,4,6,8,10,12,14 for RV64)
|
||||
* @param [in] pmpcfg PMPCFGx Register value to set
|
||||
*
|
||||
* @note Architecture-specific behavior:
|
||||
* - RV32:
|
||||
* - Each register holds 4 PMP entries
|
||||
* - Valid indices: 0 to ceil(__PMP_ENTRY_NUM/4)-1
|
||||
* - 64 entries require indices 0-15
|
||||
* - RV64:
|
||||
* - Each register holds 8 PMP entries
|
||||
* - Only even indices are valid
|
||||
* - 64 entries require indices 0,2,4,6,8,10,12,14
|
||||
*
|
||||
* @remark The function does nothing for invalid indices to prevent illegal accesses.
|
||||
*/
|
||||
__STATIC_INLINE void __set_PMPCFGx(uint32_t csr_idx, rv_csr_t pmpcfg)
|
||||
{
|
||||
switch (csr_idx) {
|
||||
#define X(n) case n: __RV_CSR_WRITE(CSR_PMPCFG##n, pmpcfg); break;
|
||||
PMPCFG_LIST
|
||||
#undef X
|
||||
default: return;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Get 8bit PMPxCFG Register by PMP entry index
|
||||
* \details Return the content of the PMPxCFG Register.
|
||||
* \param [in] entry_idx PMP region index(0-63)
|
||||
* \return PMPxCFG Register value
|
||||
*/
|
||||
__STATIC_INLINE uint8_t __get_PMPxCFG(uint32_t entry_idx)
|
||||
{
|
||||
rv_csr_t pmpcfgx = 0;
|
||||
uint8_t csr_cfg_num = 0;
|
||||
uint16_t csr_idx = 0;
|
||||
uint16_t cfg_shift = 0;
|
||||
|
||||
if (entry_idx >= __PMP_ENTRY_NUM) return 0;
|
||||
|
||||
#if __RISCV_XLEN == 32
|
||||
csr_cfg_num = 4;
|
||||
csr_idx = entry_idx >> 2;
|
||||
#elif __RISCV_XLEN == 64
|
||||
csr_cfg_num = 8;
|
||||
/* For RV64, each PMPCFG register (pmpcfg0, pmpcfg2, etc.) holds 8 PMP entries */
|
||||
/* Only even-numbered CSRs are used, so we align the index by clearing the LSB */
|
||||
csr_idx = (entry_idx >> 2) & ~1;
|
||||
#else
|
||||
// TODO Add RV128 Handling
|
||||
return 0;
|
||||
#endif
|
||||
pmpcfgx = __get_PMPCFGx(csr_idx);
|
||||
/*
|
||||
* first get specific pmpxcfg's order in one CSR composed of csr_cfg_num pmpxcfgs,
|
||||
* then get pmpxcfg's bit position in one CSR by left shift 3(each pmpxcfg size is one byte)
|
||||
*/
|
||||
cfg_shift = (entry_idx & (csr_cfg_num - 1)) << 3;
|
||||
|
||||
/* read specific pmpxcfg register value */
|
||||
return (uint8_t)(__RV_EXTRACT_FIELD(pmpcfgx, 0xFF << cfg_shift));
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Set 8bit PMPxCFG by pmp entry index
|
||||
* \details Set the given pmpxcfg value to the PMPxCFG Register.
|
||||
* \param [in] entry_idx PMPx region index(0-63)
|
||||
* \param [in] pmpxcfg PMPxCFG register value to set
|
||||
* \remark
|
||||
* - For RV32, 4 pmpxcfgs are densely packed into one CSR in order
|
||||
* For RV64, 8 pmpxcfgs are densely packed into one CSR in order
|
||||
*/
|
||||
__STATIC_INLINE void __set_PMPxCFG(uint32_t entry_idx, uint8_t pmpxcfg)
|
||||
{
|
||||
rv_csr_t pmpcfgx = 0;
|
||||
uint8_t csr_cfg_num = 0;
|
||||
uint16_t csr_idx = 0;
|
||||
uint16_t cfg_shift = 0;
|
||||
if (entry_idx >= __PMP_ENTRY_NUM) return;
|
||||
|
||||
#if __RISCV_XLEN == 32
|
||||
csr_cfg_num = 4;
|
||||
csr_idx = entry_idx >> 2;
|
||||
#elif __RISCV_XLEN == 64
|
||||
csr_cfg_num = 8;
|
||||
/* For RV64, pmpcfg0 and pmpcfg2 each hold 8 PMP entries, align by 2 */
|
||||
csr_idx = (entry_idx >> 2) & ~1;
|
||||
#else
|
||||
// TODO Add RV128 Handling
|
||||
return;
|
||||
#endif
|
||||
/* read specific pmpcfgx register value */
|
||||
pmpcfgx = __get_PMPCFGx(csr_idx);
|
||||
/*
|
||||
* first get specific pmpxcfg's order in one CSR composed of csr_cfg_num pmpxcfgs,
|
||||
* then get pmpxcfg's bit position in one CSR by left shift 3(each pmpxcfg size is one byte)
|
||||
*/
|
||||
cfg_shift = (entry_idx & (csr_cfg_num - 1)) << 3;
|
||||
|
||||
pmpcfgx = __RV_INSERT_FIELD(pmpcfgx, 0xFFUL << cfg_shift, pmpxcfg);
|
||||
__set_PMPCFGx(csr_idx, pmpcfgx);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Base PMPADDR list (indices 0-7)
|
||||
*/
|
||||
#define PMPADDR_LIST_BASE \
|
||||
X(0) X(1) X(2) X(3) X(4) X(5) X(6) X(7)
|
||||
|
||||
/**
|
||||
* @brief Extended PMPADDR list (indices 8-15)
|
||||
*/
|
||||
#define PMPADDR_LIST_8_15 \
|
||||
X(8) X(9) X(10) X(11) X(12) X(13) X(14) X(15)
|
||||
|
||||
/**
|
||||
* @brief Extended PMPADDR list (indices 16-31)
|
||||
*/
|
||||
#define PMPADDR_LIST_16_31 \
|
||||
X(16) X(17) X(18) X(19) X(20) X(21) X(22) X(23) \
|
||||
X(24) X(25) X(26) X(27) X(28) X(29) X(30) X(31)
|
||||
|
||||
/**
|
||||
* @brief Extended PMPADDR list (indices 32-63)
|
||||
*/
|
||||
#define PMPADDR_LIST_32_63 \
|
||||
X(32) X(33) X(34) X(35) X(36) X(37) X(38) X(39) \
|
||||
X(40) X(41) X(42) X(43) X(44) X(45) X(46) X(47) \
|
||||
X(48) X(49) X(50) X(51) X(52) X(53) X(54) X(55) \
|
||||
X(56) X(57) X(58) X(59) X(60) X(61) X(62) X(63)
|
||||
|
||||
/**
|
||||
* @brief Select appropriate PMPADDR list based on PMP_ENTRY_NUM
|
||||
*
|
||||
* This macro defines the complete PMPADDR list by combining base and
|
||||
* extended lists according to the configured number of PMP entries.
|
||||
*
|
||||
* @note The actual list is determined by the __PMP_ENTRY_NUM configuration:
|
||||
* - <=8: Only base list (0-7)
|
||||
* - <=16: Base + 8-15
|
||||
* - <=32: Base + 8-15 + 16-31
|
||||
* - <=64: Base + 8-15 + 16-31 + 32-63
|
||||
*/
|
||||
#if __PMP_ENTRY_NUM <= 8
|
||||
#define PMPADDR_LIST PMPADDR_LIST_BASE
|
||||
#elif __PMP_ENTRY_NUM <= 16
|
||||
#define PMPADDR_LIST PMPADDR_LIST_BASE PMPADDR_LIST_8_15
|
||||
#elif __PMP_ENTRY_NUM <= 32
|
||||
#define PMPADDR_LIST PMPADDR_LIST_BASE PMPADDR_LIST_8_15 PMPADDR_LIST_16_31
|
||||
#elif __PMP_ENTRY_NUM <= 64
|
||||
#define PMPADDR_LIST PMPADDR_LIST_BASE PMPADDR_LIST_8_15 PMPADDR_LIST_16_31 PMPADDR_LIST_32_63
|
||||
#else
|
||||
#error "Unsupported PMP_ENTRY_NUM value"
|
||||
#endif
|
||||
|
||||
/**
|
||||
* \brief Get PMPADDRx Register by CSR index
|
||||
* \details Return the content of the PMPADDRx Register.
|
||||
* \param [in] csr_idx PMP region CSR index(0-63)
|
||||
* \return PMPADDRx Register value
|
||||
*/
|
||||
__STATIC_INLINE rv_csr_t __get_PMPADDRx(uint32_t csr_idx)
|
||||
{
|
||||
switch (csr_idx) {
|
||||
#define X(n) case n: return __RV_CSR_READ(CSR_PMPADDR##n);
|
||||
PMPADDR_LIST
|
||||
#undef X
|
||||
default: return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Set PMPADDRx by CSR index
|
||||
* \details Write the given value to the PMPADDRx Register.
|
||||
* \param [in] csr_idx PMP region CSR index(0-63)
|
||||
* \param [in] pmpaddr PMPADDRx Register value to set
|
||||
*/
|
||||
__STATIC_INLINE void __set_PMPADDRx(uint32_t csr_idx, rv_csr_t pmpaddr)
|
||||
{
|
||||
switch (csr_idx) {
|
||||
#define X(n) case n: __RV_CSR_WRITE(CSR_PMPADDR##n, pmpaddr); break;
|
||||
PMPADDR_LIST
|
||||
#undef X
|
||||
default: return;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Set PMP entry by entry idx
|
||||
* \details Write the given value to the PMPxCFG Register and PMPADDRx.
|
||||
* \param [in] entry_idx PMP entry index(0-63)
|
||||
* \param [in] pmp_cfg structure of L, X, W, R field of PMP configuration register, memory region base address
|
||||
* and size of memory region as power of 2
|
||||
* \remark
|
||||
* - If the size of memory region is 2^12(4KB) range, pmp_cfg->order makes 12, and the like.
|
||||
* - Suppose the size of memory region is 2^X bytes range, if X >=3, the NA4 mode is not selectable, NAPOT is selected.
|
||||
* - TOR of A field in PMP configuration register is not considered here.
|
||||
*/
|
||||
__STATIC_INLINE void __set_PMPENTRYx(uint32_t entry_idx, const pmp_config *pmp_cfg)
|
||||
{
|
||||
unsigned int cfg_shift, cfg_csr_idx, addr_csr_idx = 0;
|
||||
unsigned long cfgmask, addrmask = 0;
|
||||
unsigned long pmpcfg, pmpaddr = 0;
|
||||
unsigned long protection, csr_cfg_num = 0;
|
||||
/* check parameters */
|
||||
if (entry_idx >= __PMP_ENTRY_NUM || pmp_cfg->order > __RISCV_XLEN || pmp_cfg->order < PMP_SHIFT) return;
|
||||
|
||||
/* calculate PMP register and offset */
|
||||
#if __RISCV_XLEN == 32
|
||||
csr_cfg_num = 4;
|
||||
cfg_csr_idx = (entry_idx >> 2);
|
||||
#elif __RISCV_XLEN == 64
|
||||
csr_cfg_num = 8;
|
||||
cfg_csr_idx = ((entry_idx >> 2)) & ~1;
|
||||
#else
|
||||
// TODO Add RV128 Handling
|
||||
return;
|
||||
#endif
|
||||
/*
|
||||
* first get specific pmpxcfg's order in one CSR composed of csr_cfg_num pmpxcfgs,
|
||||
* then get pmpxcfg's bit position in one CSR by left shift 3, each pmpxcfg size is one byte
|
||||
*/
|
||||
cfg_shift = (entry_idx & (csr_cfg_num - 1)) << 3;
|
||||
addr_csr_idx = entry_idx;
|
||||
|
||||
/* encode PMP config */
|
||||
protection = (unsigned long)pmp_cfg->protection;
|
||||
protection |= (PMP_SHIFT == pmp_cfg->order) ? PMP_A_NA4 : PMP_A_NAPOT;
|
||||
cfgmask = ~(0xFFUL << cfg_shift);
|
||||
pmpcfg = (__get_PMPCFGx(cfg_csr_idx) & cfgmask);
|
||||
pmpcfg |= ((protection << cfg_shift) & ~cfgmask);
|
||||
|
||||
/* encode PMP address */
|
||||
if (PMP_SHIFT == pmp_cfg->order) { /* NA4 */
|
||||
pmpaddr = (pmp_cfg->base_addr >> PMP_SHIFT);
|
||||
} else { /* NAPOT */
|
||||
addrmask = (1UL << (pmp_cfg->order - PMP_SHIFT)) - 1;
|
||||
pmpaddr = ((pmp_cfg->base_addr >> PMP_SHIFT) & ~addrmask);
|
||||
pmpaddr |= (addrmask >> 1);
|
||||
}
|
||||
/*
|
||||
* write csrs, update the address first, in case the entry is locked that
|
||||
* we won't be able to modify it after we set the config csr.
|
||||
*/
|
||||
__set_PMPADDRx(addr_csr_idx, pmpaddr);
|
||||
__set_PMPCFGx(cfg_csr_idx, pmpcfg);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Get PMP entry by entry idx
|
||||
* \details Write the given value to the PMPxCFG Register and PMPADDRx.
|
||||
* \param [in] entry_idx PMP entry index(0-63)
|
||||
* \param [out] pmp_cfg structure of L, X, W, R, A field of PMP configuration register, memory region base
|
||||
* address and size of memory region as power of 2
|
||||
* \return -1 failure, else 0 success
|
||||
* \remark
|
||||
* - If the size of memory region is 2^12(4KB) range, pmp_cfg->order makes 12, and the like.
|
||||
* - TOR of A field in PMP configuration register is not considered here.
|
||||
*/
|
||||
__STATIC_INLINE int __get_PMPENTRYx(unsigned int entry_idx, pmp_config *pmp_cfg)
|
||||
{
|
||||
unsigned int cfg_shift, cfg_csr_idx, addr_csr_idx = 0;
|
||||
unsigned long cfgmask, pmpcfg, prot = 0;
|
||||
unsigned long t1, addr, pmpaddr, len = 0;
|
||||
uint8_t csr_cfg_num = 0;
|
||||
/* check parameters */
|
||||
if (entry_idx >= __PMP_ENTRY_NUM || !pmp_cfg) return -1;
|
||||
|
||||
/* calculate PMP register and offset */
|
||||
#if __RISCV_XLEN == 32
|
||||
csr_cfg_num = 4;
|
||||
cfg_csr_idx = entry_idx >> 2;
|
||||
#elif __RISCV_XLEN == 64
|
||||
csr_cfg_num = 8;
|
||||
cfg_csr_idx = (entry_idx>> 2) & ~1;
|
||||
#else
|
||||
// TODO Add RV128 Handling
|
||||
return -1;
|
||||
#endif
|
||||
|
||||
cfg_shift = (entry_idx & (csr_cfg_num - 1)) << 3;
|
||||
addr_csr_idx = entry_idx;
|
||||
|
||||
/* decode PMP config */
|
||||
cfgmask = (0xFFUL << cfg_shift);
|
||||
pmpcfg = (__get_PMPCFGx(cfg_csr_idx) & cfgmask);
|
||||
prot = pmpcfg >> cfg_shift;
|
||||
|
||||
/* decode PMP address */
|
||||
pmpaddr = __get_PMPADDRx(addr_csr_idx);
|
||||
if (PMP_A_NAPOT == (prot & PMP_A)) {
|
||||
t1 = __CTZ(~pmpaddr);
|
||||
addr = (pmpaddr & ~((1UL << t1) - 1)) << PMP_SHIFT;
|
||||
len = (t1 + PMP_SHIFT + 1);
|
||||
} else {
|
||||
addr = pmpaddr << PMP_SHIFT;
|
||||
len = PMP_SHIFT;
|
||||
}
|
||||
|
||||
/* return details */
|
||||
pmp_cfg->protection = prot;
|
||||
pmp_cfg->base_addr = addr;
|
||||
pmp_cfg->order = len;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** @} */ /* End of Doxygen Group NMSIS_Core_PMP_Functions */
|
||||
#endif /* defined(__PMP_PRESENT) && (__PMP_PRESENT == 1) */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif /* __CORE_FEATURE_PMP_H__ */
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,457 @@
|
||||
/*
|
||||
* Copyright (c) 2019 Nuclei Limited. All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* 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 __CORE_FEATURE_SPMP_H__
|
||||
#define __CORE_FEATURE_SPMP_H__
|
||||
/*!
|
||||
* @file core_feature_spmp.h
|
||||
* @brief sPMP(has upgraded to S-mode Memory Protection Unit, renamed as SMPU) feature API header file for Nuclei N/NX Core
|
||||
*/
|
||||
/*
|
||||
* sPMP Feature Configuration Macro:
|
||||
* 1. __SPMP_PRESENT: Define whether sPMP is present or not
|
||||
* __SMPU_PRESENT: Define whether SMPU is present or not
|
||||
* * 0: Not present
|
||||
* * 1: Present
|
||||
* 2. __SPMP_ENTRY_NUM: Define the number of sPMP entries, only 8 or 16 is configurable
|
||||
* __SMPU_ENTRY_NUM: Define the number of SMPU entries, only 8 or 16 is configurable
|
||||
* __SMPU_ENTRY_NUM is the same as __SPMP_ENTRY_NUM
|
||||
*/
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "core_feature_base.h"
|
||||
#include "core_compatiable.h"
|
||||
|
||||
#if defined(__SPMP_PRESENT) && (__SPMP_PRESENT == 1)
|
||||
|
||||
/* ===== sPMP Operations ===== */
|
||||
/**
|
||||
* \defgroup NMSIS_Core_SPMP sPMP or sMPU Functions
|
||||
* \ingroup NMSIS_Core
|
||||
* \brief Functions that related to the RISCV supervisor-mode Phyiscal Memory Protection.
|
||||
* \details
|
||||
* Optional superviosr physical memory protection (sPMP) unit provides per-hart supervisor-mode
|
||||
* control registers to allow physical memory access privileges (read, write, execute)
|
||||
* to be specified for each physical memory region. The sPMP values are checked after the physical
|
||||
* address to be accessed pass PMP checks described in the RISC-V privileged spec.
|
||||
*
|
||||
* Like PMP, the sPMP can supports region access control settings as small as four bytes.
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
#ifndef __SPMP_ENTRY_NUM
|
||||
/* Number of __SPMP_ENTRY_NUM entries should be defined in <Device.h> */
|
||||
#error "__SPMP_ENTRY_NUM is not defined, please check!"
|
||||
#endif
|
||||
|
||||
typedef struct SPMP_CONFIG {
|
||||
/**
|
||||
* Set permissions using macros \ref SMPU_S/\ref SMPU_R/\ref SMPU_W/\ref SMPU_X of SMPU;
|
||||
* \ref SPMP_L/\ref SPMP_U/\ref SPMP_R/\ref SPMP_W/\ref SPMP_X of sPMP,
|
||||
* see details in riscv spec of SMPU/sPMP
|
||||
*/
|
||||
unsigned int protection;
|
||||
/**
|
||||
* Size of memory region as power of 2, it has to be minimum 2 and maxium \ref __RISCV_XLEN according to the
|
||||
* hardwired granularity 2^N bytes, if N = 12, then order has to be at least 12; if not, the order read out
|
||||
* is N though you configure less than N. Generally, Nuclei CPU's smpu granularity is 2^12 = 4KBytes, you should refer to the databook.
|
||||
*/
|
||||
unsigned long order;
|
||||
/**
|
||||
* Base address of memory region
|
||||
* It must be 2^order aligned address
|
||||
*/
|
||||
unsigned long base_addr;
|
||||
} spmp_config;
|
||||
|
||||
/**
|
||||
* \brief Get sPMPCFGx Register by csr index
|
||||
* \details Return the content of the sPMPCFGx Register.
|
||||
* \param [in] csr_idx sPMPCFG CSR index(0-3)
|
||||
* \return sPMPCFGx Register value
|
||||
* \remark
|
||||
* - For RV64, only csr_idx = 0 and csr_idx = 2 is allowed.
|
||||
* spmpcfg0 and spmpcfg2 hold the configurations
|
||||
* for the 16 sPMP entries, spmpcfg1 and spmpcfg3 are illegal
|
||||
* - For RV32, spmpcfg0–spmpcfg3, hold the configurations
|
||||
* spmp0cfg–spmp15cfg for the 16 sPMP entries
|
||||
*/
|
||||
__STATIC_INLINE rv_csr_t __get_sPMPCFGx(uint32_t csr_idx)
|
||||
{
|
||||
switch (csr_idx) {
|
||||
case 0: return __RV_CSR_READ(CSR_SPMPCFG0);
|
||||
case 1: return __RV_CSR_READ(CSR_SPMPCFG1);
|
||||
#if __SPMP_ENTRY_NUM > 8
|
||||
case 2: return __RV_CSR_READ(CSR_SPMPCFG2);
|
||||
case 3: return __RV_CSR_READ(CSR_SPMPCFG3);
|
||||
#endif
|
||||
default: return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Set sPMPCFGx by csr index
|
||||
* \details Write the given value to the sPMPCFGx Register.
|
||||
* \param [in] csr_idx sPMPCFG CSR index(0-3)
|
||||
* \param [in] spmpcfg sPMPCFGx Register value to set
|
||||
* \remark
|
||||
* - For RV64, only csr_idx = 0 and csr_idx = 2 is allowed.
|
||||
* spmpcfg0 and spmpcfg2 hold the configurations
|
||||
* for the 16 sPMP entries, spmpcfg1 and spmpcfg3 are illegal
|
||||
* - For RV32, spmpcfg0–spmpcfg3, hold the configurations
|
||||
* spmp0cfg–spmp15cfg for the 16 sPMP entries
|
||||
*/
|
||||
__STATIC_INLINE void __set_sPMPCFGx(uint32_t csr_idx, rv_csr_t spmpcfg)
|
||||
{
|
||||
switch (csr_idx) {
|
||||
case 0: __RV_CSR_WRITE(CSR_SPMPCFG0, spmpcfg); break;
|
||||
case 1: __RV_CSR_WRITE(CSR_SPMPCFG1, spmpcfg); break;
|
||||
#if __SPMP_ENTRY_NUM > 8
|
||||
case 2: __RV_CSR_WRITE(CSR_SPMPCFG2, spmpcfg); break;
|
||||
case 3: __RV_CSR_WRITE(CSR_SPMPCFG3, spmpcfg); break;
|
||||
#endif
|
||||
default: return;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Get 8bit sPMPxCFG Register by sPMP entry index
|
||||
* \details Return the content of the sPMPxCFG Register.
|
||||
* \param [in] entry_idx sPMP region index(0-15)
|
||||
* \return sPMPxCFG Register value
|
||||
*/
|
||||
__STATIC_INLINE uint8_t __get_sPMPxCFG(uint32_t entry_idx)
|
||||
{
|
||||
rv_csr_t spmpcfgx = 0;
|
||||
uint8_t csr_cfg_num = 0;
|
||||
uint16_t csr_idx = 0;
|
||||
uint16_t cfg_shift = 0;
|
||||
|
||||
if (entry_idx >= __SPMP_ENTRY_NUM) return 0;
|
||||
|
||||
#if __RISCV_XLEN == 32
|
||||
csr_cfg_num = 4;
|
||||
csr_idx = entry_idx >> 2;
|
||||
#elif __RISCV_XLEN == 64
|
||||
csr_cfg_num = 8;
|
||||
/* For RV64, spmpcfg0 and spmpcfg2 each hold 8 sPMP entries, align by 2 */
|
||||
csr_idx = (entry_idx >> 2) & ~1;
|
||||
#else
|
||||
// TODO Add RV128 Handling
|
||||
return 0;
|
||||
#endif
|
||||
spmpcfgx = __get_sPMPCFGx(csr_idx);
|
||||
/*
|
||||
* first get specific spmpxcfg's order in one CSR composed of csr_cfg_num spmpxcfgs,
|
||||
* then get spmpxcfg's bit position in one CSR by left shift 3(each spmpxcfg size is one byte)
|
||||
*/
|
||||
cfg_shift = (entry_idx & (csr_cfg_num - 1)) << 3;
|
||||
|
||||
/* read specific spmpxcfg register value */
|
||||
return (uint8_t)(__RV_EXTRACT_FIELD(spmpcfgx, 0xFF << cfg_shift));
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Set 8bit sPMPxCFG by spmp entry index
|
||||
* \details Set the given spmpxcfg value to the sPMPxCFG Register.
|
||||
* \param [in] entry_idx sPMPx region index(0-15)
|
||||
* \param [in] spmpxcfg sPMPxCFG register value to set
|
||||
* \remark
|
||||
* - For RV32, 4 spmpxcfgs are densely packed into one CSR in order
|
||||
* For RV64, 8 spmpxcfgs are densely packed into one CSR in order
|
||||
*/
|
||||
__STATIC_INLINE void __set_sPMPxCFG(uint32_t entry_idx, uint8_t spmpxcfg)
|
||||
{
|
||||
rv_csr_t spmpcfgx = 0;
|
||||
uint8_t csr_cfg_num = 0;
|
||||
uint16_t csr_idx = 0;
|
||||
uint16_t cfg_shift = 0;
|
||||
if (entry_idx >= __SPMP_ENTRY_NUM) return;
|
||||
|
||||
#if __RISCV_XLEN == 32
|
||||
csr_cfg_num = 4;
|
||||
csr_idx = entry_idx >> 2;
|
||||
#elif __RISCV_XLEN == 64
|
||||
csr_cfg_num = 8;
|
||||
/* For RV64, spmpcfg0 and spmpcfg2 each hold 8 sPMP entries, align by 2 */
|
||||
csr_idx = (entry_idx >> 2) & ~1;
|
||||
#else
|
||||
// TODO Add RV128 Handling
|
||||
return;
|
||||
#endif
|
||||
/* read specific spmpcfgx register value */
|
||||
spmpcfgx = __get_sPMPCFGx(csr_idx);
|
||||
/*
|
||||
* first get specific spmpxcfg's order in one CSR composed of csr_cfg_num spmpxcfgs,
|
||||
* then get spmpxcfg's bit position in one CSR by left shift 3(each spmpxcfg size is one byte)
|
||||
*/
|
||||
cfg_shift = (entry_idx & (csr_cfg_num - 1)) << 3;
|
||||
|
||||
spmpcfgx = __RV_INSERT_FIELD(spmpcfgx, 0xFFUL << cfg_shift, spmpxcfg);
|
||||
__set_sPMPCFGx(csr_idx, spmpcfgx);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Get sPMPADDRx Register by CSR index
|
||||
* \details Return the content of the sPMPADDRx Register.
|
||||
* \param [in] csr_idx sPMP region CSR index(0-15)
|
||||
* \return sPMPADDRx Register value
|
||||
*/
|
||||
__STATIC_INLINE rv_csr_t __get_sPMPADDRx(uint32_t csr_idx)
|
||||
{
|
||||
switch (csr_idx) {
|
||||
case 0: return __RV_CSR_READ(CSR_SPMPADDR0);
|
||||
case 1: return __RV_CSR_READ(CSR_SPMPADDR1);
|
||||
case 2: return __RV_CSR_READ(CSR_SPMPADDR2);
|
||||
case 3: return __RV_CSR_READ(CSR_SPMPADDR3);
|
||||
case 4: return __RV_CSR_READ(CSR_SPMPADDR4);
|
||||
case 5: return __RV_CSR_READ(CSR_SPMPADDR5);
|
||||
case 6: return __RV_CSR_READ(CSR_SPMPADDR6);
|
||||
case 7: return __RV_CSR_READ(CSR_SPMPADDR7);
|
||||
#if __SPMP_ENTRY_NUM > 8
|
||||
case 8: return __RV_CSR_READ(CSR_SPMPADDR8);
|
||||
case 9: return __RV_CSR_READ(CSR_SPMPADDR9);
|
||||
case 10: return __RV_CSR_READ(CSR_SPMPADDR10);
|
||||
case 11: return __RV_CSR_READ(CSR_SPMPADDR11);
|
||||
case 12: return __RV_CSR_READ(CSR_SPMPADDR12);
|
||||
case 13: return __RV_CSR_READ(CSR_SPMPADDR13);
|
||||
case 14: return __RV_CSR_READ(CSR_SPMPADDR14);
|
||||
case 15: return __RV_CSR_READ(CSR_SPMPADDR15);
|
||||
#endif
|
||||
default: return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Set sPMPADDRx by CSR index
|
||||
* \details Write the given value to the sPMPADDRx Register.
|
||||
* \param [in] csr_idx sPMP region CSR index(0-15)
|
||||
* \param [in] spmpaddr sPMPADDRx Register value to set
|
||||
*/
|
||||
__STATIC_INLINE void __set_sPMPADDRx(uint32_t csr_idx, rv_csr_t spmpaddr)
|
||||
{
|
||||
switch (csr_idx) {
|
||||
case 0: __RV_CSR_WRITE(CSR_SPMPADDR0, spmpaddr); break;
|
||||
case 1: __RV_CSR_WRITE(CSR_SPMPADDR1, spmpaddr); break;
|
||||
case 2: __RV_CSR_WRITE(CSR_SPMPADDR2, spmpaddr); break;
|
||||
case 3: __RV_CSR_WRITE(CSR_SPMPADDR3, spmpaddr); break;
|
||||
case 4: __RV_CSR_WRITE(CSR_SPMPADDR4, spmpaddr); break;
|
||||
case 5: __RV_CSR_WRITE(CSR_SPMPADDR5, spmpaddr); break;
|
||||
case 6: __RV_CSR_WRITE(CSR_SPMPADDR6, spmpaddr); break;
|
||||
case 7: __RV_CSR_WRITE(CSR_SPMPADDR7, spmpaddr); break;
|
||||
#if __SPMP_ENTRY_NUM > 8
|
||||
case 8: __RV_CSR_WRITE(CSR_SPMPADDR8, spmpaddr); break;
|
||||
case 9: __RV_CSR_WRITE(CSR_SPMPADDR9, spmpaddr); break;
|
||||
case 10: __RV_CSR_WRITE(CSR_SPMPADDR10, spmpaddr); break;
|
||||
case 11: __RV_CSR_WRITE(CSR_SPMPADDR11, spmpaddr); break;
|
||||
case 12: __RV_CSR_WRITE(CSR_SPMPADDR12, spmpaddr); break;
|
||||
case 13: __RV_CSR_WRITE(CSR_SPMPADDR13, spmpaddr); break;
|
||||
case 14: __RV_CSR_WRITE(CSR_SPMPADDR14, spmpaddr); break;
|
||||
case 15: __RV_CSR_WRITE(CSR_SPMPADDR15, spmpaddr); break;
|
||||
#endif
|
||||
default: return;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Set sPMP entry by entry idx
|
||||
* \details Write the given value to the sPMPxCFG Register and sPMPADDRx.
|
||||
* \param [in] entry_idx sPMP entry index(0-15)
|
||||
* \param [in] spmp_cfg structure of L,U,X,W,R field of sPMP configuration register, memory region base address
|
||||
* and size of memory region as power of 2
|
||||
* \remark
|
||||
* - If the size of memory region is 2^12(4KB) range, spmp_cfg->order makes 12, and the like.
|
||||
* - Suppose the size of memory region is 2^X bytes range, if X >=3, the NA4 mode is not selectable, NAPOT is selected.
|
||||
* - TOR of A field in sPMP configuration register is not considered here.
|
||||
*/
|
||||
__STATIC_INLINE void __set_sPMPENTRYx(uint32_t entry_idx, const spmp_config *spmp_cfg)
|
||||
{
|
||||
unsigned int cfg_shift, cfg_csr_idx, addr_csr_idx = 0;
|
||||
unsigned long cfgmask, addrmask = 0;
|
||||
unsigned long spmpcfg, spmpaddr = 0;
|
||||
unsigned long protection, csr_cfg_num = 0;
|
||||
/* check parameters */
|
||||
if (entry_idx >= __SPMP_ENTRY_NUM || spmp_cfg->order > __RISCV_XLEN || spmp_cfg->order < SPMP_SHIFT) return;
|
||||
|
||||
/* calculate sPMP register and offset */
|
||||
#if __RISCV_XLEN == 32
|
||||
csr_cfg_num = 4;
|
||||
cfg_csr_idx = (entry_idx >> 2);
|
||||
#elif __RISCV_XLEN == 64
|
||||
csr_cfg_num = 8;
|
||||
cfg_csr_idx = ((entry_idx >> 2)) & ~1;
|
||||
#else
|
||||
// TODO Add RV128 Handling
|
||||
return;
|
||||
#endif
|
||||
/*
|
||||
* first get specific spmpxcfg's order in one CSR composed of csr_cfg_num spmpxcfgs,
|
||||
* then get spmpxcfg's bit position in one CSR by left shift 3, each spmpxcfg size is one byte
|
||||
*/
|
||||
cfg_shift = (entry_idx & (csr_cfg_num - 1)) << 3;
|
||||
addr_csr_idx = entry_idx;
|
||||
|
||||
/* encode sPMP config */
|
||||
protection = (unsigned long)spmp_cfg->protection;
|
||||
protection |= (SPMP_SHIFT == spmp_cfg->order) ? SPMP_A_NA4 : SPMP_A_NAPOT;
|
||||
cfgmask = ~(0xFFUL << cfg_shift);
|
||||
spmpcfg = (__get_sPMPCFGx(cfg_csr_idx) & cfgmask);
|
||||
spmpcfg |= ((protection << cfg_shift) & ~cfgmask);
|
||||
|
||||
/* encode sPMP address */
|
||||
if (SPMP_SHIFT == spmp_cfg->order) { /* NA4 */
|
||||
spmpaddr = (spmp_cfg->base_addr >> SPMP_SHIFT);
|
||||
} else { /* NAPOT */
|
||||
addrmask = (1UL << (spmp_cfg->order - SPMP_SHIFT)) - 1;
|
||||
spmpaddr = ((spmp_cfg->base_addr >> SPMP_SHIFT) & ~addrmask);
|
||||
spmpaddr |= (addrmask >> 1);
|
||||
}
|
||||
/*
|
||||
* write csrs, update the address first, in case the entry is locked that
|
||||
* we won't be able to modify it after we set the config csr.
|
||||
*/
|
||||
__set_sPMPADDRx(addr_csr_idx, spmpaddr);
|
||||
__set_sPMPCFGx(cfg_csr_idx, spmpcfg);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Get sPMP entry by entry idx
|
||||
* \details Write the given value to the sPMPxCFG Register and sPMPADDRx.
|
||||
* \param [in] entry_idx sPMP entry index(0-15)
|
||||
* \param [out] spmp_cfg structure of L, U, X, W, R, A field of sPMP configuration register, memory region base
|
||||
* address and size of memory region as power of 2
|
||||
* \return -1 failure, else 0 success
|
||||
* \remark
|
||||
* - If the size of memory region is 2^12(4KB) range, spmp_cfg->order makes 12, and the like.
|
||||
* - TOR of A field in PMP configuration register is not considered here.
|
||||
*/
|
||||
__STATIC_INLINE int __get_sPMPENTRYx(unsigned int entry_idx, spmp_config *spmp_cfg)
|
||||
{
|
||||
unsigned int cfg_shift, cfg_csr_idx, addr_csr_idx = 0;
|
||||
unsigned long cfgmask, spmpcfg, prot = 0;
|
||||
unsigned long t1, addr, spmpaddr, len = 0;
|
||||
uint8_t csr_cfg_num = 0;
|
||||
/* check parameters */
|
||||
if (entry_idx >= __SPMP_ENTRY_NUM || !spmp_cfg) return -1;
|
||||
|
||||
/* calculate sPMP register and offset */
|
||||
#if __RISCV_XLEN == 32
|
||||
csr_cfg_num = 4;
|
||||
cfg_csr_idx = entry_idx >> 2;
|
||||
#elif __RISCV_XLEN == 64
|
||||
csr_cfg_num = 8;
|
||||
cfg_csr_idx = (entry_idx >> 2) & ~1;
|
||||
#else
|
||||
// TODO Add RV128 Handling
|
||||
return -1;
|
||||
#endif
|
||||
|
||||
cfg_shift = (entry_idx & (csr_cfg_num - 1)) << 3;
|
||||
addr_csr_idx = entry_idx;
|
||||
|
||||
/* decode sPMP config */
|
||||
cfgmask = (0xFFUL << cfg_shift);
|
||||
spmpcfg = (__get_sPMPCFGx(cfg_csr_idx) & cfgmask);
|
||||
prot = spmpcfg >> cfg_shift;
|
||||
|
||||
/* decode sPMP address */
|
||||
spmpaddr = __get_sPMPADDRx(addr_csr_idx);
|
||||
if (SPMP_A_NAPOT == (prot & SPMP_A)) {
|
||||
t1 = __CTZ(~spmpaddr);
|
||||
addr = (spmpaddr & ~((1UL << t1) - 1)) << SPMP_SHIFT;
|
||||
len = (t1 + SPMP_SHIFT + 1);
|
||||
} else {
|
||||
addr = spmpaddr << SPMP_SHIFT;
|
||||
len = SPMP_SHIFT;
|
||||
}
|
||||
|
||||
/* return details */
|
||||
spmp_cfg->protection = prot;
|
||||
spmp_cfg->base_addr = addr;
|
||||
spmp_cfg->order = len;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if defined(__SMPU_PRESENT) && (__SMPU_PRESENT == 1)
|
||||
/**
|
||||
* sPMP has upgraded to S-mode Memory Protection Unit, renamed as SMPU, but still share the apis with sPMP's
|
||||
*/
|
||||
typedef spmp_config smpu_config;
|
||||
#define __get_SMPUCFGx __get_sPMPCFGx
|
||||
#define __set_SMPUCFGx __set_sPMPCFGx
|
||||
#define __get_SMPUxCFG __get_sPMPxCFG
|
||||
#define __set_SMPUxCFG __set_sPMPxCFG
|
||||
#define __get_SMPUADDRx __get_sPMPADDRx
|
||||
#define __set_SMPUADDRx __set_sPMPADDRx
|
||||
#define __set_SMPUENTRYx __set_sPMPENTRYx
|
||||
#define __get_SMPUENTRYx __get_sPMPENTRYx
|
||||
|
||||
/**
|
||||
* \brief Set SMPU each entry's on/off status
|
||||
* \details Write the given value to the SMPUSWITCHx Register.
|
||||
* \param [in] val activate each entry(max to 64) or not
|
||||
* \remark
|
||||
* - Each bit of this register holds on/off status of the corresponding SMPU entry respectively.
|
||||
* - An SMPU entry is activated only when both corresponding bits in smpuswitch and
|
||||
* A field of smpuicfg are set. (i.e., smpuswitch[i] & smpu[i]cfg.A).
|
||||
*/
|
||||
__STATIC_INLINE void __set_SMPUSWITCHx(uint64_t val)
|
||||
{
|
||||
#if __RISCV_XLEN == 32
|
||||
__RV_CSR_WRITE(CSR_SMPUSWITCH0, (uint32_t)val);
|
||||
__RV_CSR_WRITE(CSR_SMPUSWITCH1, (uint32_t)(val >> 32));
|
||||
#elif __RISCV_XLEN == 64
|
||||
__RV_CSR_WRITE(CSR_SMPUSWITCH0, val);
|
||||
#else
|
||||
// TODO Add RV128 Handling
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Get SMPU each entry's on/off status
|
||||
* \details Get the value of the SMPUSWITCHx Register.
|
||||
* \remark
|
||||
* - Each bit of this register holds on/off status of the corresponding SMPU entry respectively.
|
||||
* - An SMPU entry is activated only when both corresponding bits in smpuswitch and
|
||||
* A field of smpuicfg are set. (i.e., smpuswitch[i] & smpu[i]cfg.A).
|
||||
*/
|
||||
__STATIC_INLINE uint64_t __get_SMPUSWITCHx(void)
|
||||
{
|
||||
#if __RISCV_XLEN == 32
|
||||
uint32_t lo, hi = 0;
|
||||
lo = __RV_CSR_READ(CSR_SMPUSWITCH0);
|
||||
hi = __RV_CSR_READ(CSR_SMPUSWITCH1);
|
||||
return (uint64_t)((((uint64_t)hi) << 32) | lo);
|
||||
#elif __RISCV_XLEN == 64
|
||||
return (uint64_t)__RV_CSR_READ(CSR_SMPUSWITCH0);
|
||||
#else
|
||||
// TODO Add RV128 Handling
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/** @} */ /* End of Doxygen Group NMSIS_Core_SPMP_Functions */
|
||||
#endif /* defined(__SPMP_PRESENT) && (__SPMP_PRESENT == 1) */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif /* __CORE_FEATURE_SPMP_H__ */
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,95 @@
|
||||
/*
|
||||
* Copyright (c) 2019 Nuclei Limited. All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* 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 __CORE_FEATURE_VECTOR__
|
||||
#define __CORE_FEATURE_VECTOR__
|
||||
|
||||
/*!
|
||||
* @file core_feature_vector.h
|
||||
* @brief Vector feature API header file for Nuclei N/NX Core
|
||||
*/
|
||||
/*
|
||||
* Vector Feature Configuration Macro:
|
||||
* 1. __VECTOR_PRESENT: Define whether Vector Unit is present or not
|
||||
* * 0: Not present
|
||||
* * 1: Present
|
||||
*/
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "core_feature_base.h"
|
||||
|
||||
#if defined(__VECTOR_PRESENT) && (__VECTOR_PRESENT == 1)
|
||||
|
||||
/* ########################### CPU Vector Intrinsic Functions ########################### */
|
||||
/**
|
||||
* \defgroup NMSIS_Core_Vector_Intrinsic Intrinsic Functions for Vector Instructions
|
||||
* \ingroup NMSIS_Core
|
||||
* \brief Functions that generate RISC-V Vector instructions.
|
||||
* \details
|
||||
*
|
||||
* RISC-V Vector Intrinsic APIs are provided directly through compiler generated intrinsic function.
|
||||
*
|
||||
* This intrinsic function support by compiler:
|
||||
*
|
||||
* For Nuclei RISC-V GCC 10.2, it is an very old and not ratified version(no longer supported).
|
||||
*
|
||||
* - API header file can be found in lib/gcc/riscv-nuclei-elf/<gcc_ver>/include/riscv_vector.h
|
||||
*
|
||||
* For Nuclei RISC-V GCC 13/Clang 17, the intrinsic API supported is v0.12 version, see
|
||||
* https://github.com/riscv-non-isa/rvv-intrinsic-doc/releases/tag/v0.12.0
|
||||
*
|
||||
* For Nuclei RISC-V GCC 14.2/Clang 19, the intrinsic API supported is v0.11.x version, see
|
||||
* https://github.com/riscv-non-isa/rvv-intrinsic-doc/tree/v0.11.x
|
||||
* @{
|
||||
*/
|
||||
|
||||
#if defined(__INC_INTRINSIC_API) && (__INC_INTRINSIC_API == 1)
|
||||
#include <riscv_vector.h>
|
||||
#endif
|
||||
|
||||
/**
|
||||
* \brief Enable Vector Unit
|
||||
* \details
|
||||
* Set vector context status bits to enable vector unit,
|
||||
* and set state to initial
|
||||
*/
|
||||
__STATIC_FORCEINLINE void __enable_vector(void)
|
||||
{
|
||||
__RV_CSR_CLEAR(CSR_MSTATUS, MSTATUS_VS);
|
||||
__RV_CSR_SET(CSR_MSTATUS, MSTATUS_VS_INITIAL);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Disable Vector Unit
|
||||
* \details
|
||||
* Clear vector context status bits to disable vector unit
|
||||
*/
|
||||
__STATIC_FORCEINLINE void __disable_vector(void)
|
||||
{
|
||||
__RV_CSR_CLEAR(CSR_MSTATUS, MSTATUS_VS);
|
||||
}
|
||||
|
||||
/** @} */ /* End of Doxygen Group NMSIS_Core_Vector_Intrinsic */
|
||||
#endif /* defined(__VECTOR_PRESENT) && (__VECTOR_PRESENT == 1) */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __CORE_FEATURE_VECTOR__ */
|
||||
@@ -0,0 +1,427 @@
|
||||
/*
|
||||
* Copyright (c) 2019 Nuclei Limited. All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* 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 __NMSIS_BENCH__
|
||||
#define __NMSIS_BENCH__
|
||||
|
||||
/*!
|
||||
* @file nmsis_bench.h
|
||||
* @brief benchmark and helper related API for Nuclei N/NX Core
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "core_feature_base.h"
|
||||
#include <stdio.h>
|
||||
|
||||
#ifdef BENCH_XLEN_MODE
|
||||
typedef unsigned long Bench_Type;
|
||||
#else
|
||||
#if defined(CPU_SERIES) && CPU_SERIES == 100
|
||||
typedef uint32_t Bench_Type;
|
||||
#else
|
||||
typedef uint64_t Bench_Type;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/**
|
||||
* \defgroup NMSIS_Core_Bench_Helpers NMSIS Bench and Test Related Helper Functions
|
||||
* \ingroup NMSIS_Core
|
||||
* \brief Functions that used to do benchmark and test suite.
|
||||
* \details
|
||||
*
|
||||
* NMSIS benchmark and test related helper functions are provided to help do benchmark
|
||||
* and test case pass/fail assertion.
|
||||
*
|
||||
* If you want to do calculate cpu cycle cost of a process, you can use BENCH_xxx macros
|
||||
* defined in this.
|
||||
*
|
||||
* In a single c source code file, you should include `nmsis_bench.h`, and then you should place `BENCH_DECLARE_VAR();`
|
||||
* before call other BENCH_xxx macros. If you want to start to do benchmark, you should only call `BENCH_INIT();`
|
||||
* once in your source code, and then place `BENCH_START(proc_name);` and `BENCH_END(proc_name)` before
|
||||
* and after the process you want to measure. You can refer to `<nuclei-sdk>/application/baremetal/demo_dsp`
|
||||
* for how to use it.
|
||||
*
|
||||
* If you want to disable the benchmark calculation, you can place `#define DISABLE_NMSIS_BENCH`
|
||||
* before include `nmsis_bench.h`
|
||||
*
|
||||
* If in your c test source code, you can add `NMSIS_TEST_PASS();` and `NMSIS_TEST_FAIL();` to mark c test
|
||||
* is pass or fail.
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* \brief Prepare benchmark environment
|
||||
* \details
|
||||
* Prepare benchmark required environment, such as turn on necessary units
|
||||
* like vpu, cycle, instret counters, hpm counters
|
||||
*/
|
||||
__STATIC_FORCEINLINE void __prepare_bench_env(void)
|
||||
{
|
||||
#ifdef __riscv_vector
|
||||
__RV_CSR_SET(CSR_MSTATUS, MSTATUS_VS);
|
||||
#endif
|
||||
__enable_all_counter();
|
||||
}
|
||||
|
||||
#ifndef READ_CYCLE
|
||||
/**
|
||||
* When XLEN=32, reading the full 64-bit CYCLE register incurs additional overhead.
|
||||
* `BENCH_XLEN_MODE` skips reading the upper 32 bits, reducing the extra cycle cost
|
||||
* and allowing for more accurate measurements of small cycle counts.
|
||||
*
|
||||
* NOTE: It is only applicable when the total cycle count does not exceed 2^32.
|
||||
*
|
||||
*/
|
||||
#ifdef BENCH_XLEN_MODE
|
||||
/** Read single CYCLE register */
|
||||
#define READ_CYCLE __read_cycle_csr
|
||||
#else
|
||||
/** Read the whole 64 bits value of MCYCLE register */
|
||||
#define READ_CYCLE __get_rv_cycle
|
||||
#endif /* #ifdef BENCH_XLEN_MODE */
|
||||
#endif /* #ifndef READ_CYCLE */
|
||||
|
||||
#ifndef DISABLE_NMSIS_BENCH
|
||||
|
||||
/** Declare benchmark required variables, need to be placed above all BENCH_xxx macros in each c source code if BENCH_xxx used */
|
||||
#define BENCH_DECLARE_VAR() static volatile Bench_Type _bc_sttcyc, _bc_endcyc, _bc_usecyc, _bc_sumcyc; \
|
||||
static volatile unsigned long _bc_lpcnt, _bc_ercd;
|
||||
|
||||
/** Initialize benchmark environment, need to called in before other BENCH_xxx macros are called */
|
||||
#define BENCH_INIT() printf("Benchmark initialized\n"); \
|
||||
__prepare_bench_env(); \
|
||||
_bc_ercd = 0; _bc_sumcyc = 0;
|
||||
|
||||
/** Reset benchmark sum cycle and use cycle for proc */
|
||||
#define BENCH_RESET(proc) _bc_sumcyc = 0; _bc_usecyc = 0; _bc_lpcnt = 0; _bc_ercd = 0;
|
||||
|
||||
/** Start to do benchmark for proc, and record start cycle, and reset error code */
|
||||
#define BENCH_START(proc) _bc_ercd = 0; \
|
||||
_bc_sttcyc = READ_CYCLE();
|
||||
|
||||
/** Sample a benchmark for proc, and record this start -> sample cost cycle, and accumulate it to sum cycle */
|
||||
#define BENCH_SAMPLE(proc) _bc_endcyc = READ_CYCLE(); \
|
||||
_bc_usecyc = _bc_endcyc - _bc_sttcyc; \
|
||||
_bc_sumcyc += _bc_usecyc; _bc_lpcnt += 1;
|
||||
|
||||
/** Mark end of benchmark for proc, and calc used cycle, and print it */
|
||||
#define BENCH_END(proc) BENCH_SAMPLE(proc); \
|
||||
printf("CSV, %s, %lu\n", #proc, (unsigned long)_bc_usecyc);
|
||||
|
||||
/** Mark stop of benchmark, start -> sample -> sample -> stop, and print the sum cycle of a proc */
|
||||
#define BENCH_STOP(proc) printf("CSV, %s, %lu\n", #proc, (unsigned long)_bc_sumcyc);
|
||||
|
||||
/** Show statistics of benchmark, format: STAT, proc, loopcnt, sumcyc */
|
||||
#define BENCH_STAT(proc) printf("STAT, %s, %lu, %lu\n", #proc, (unsigned long)_bc_lpcnt, (unsigned long)_bc_sumcyc);
|
||||
|
||||
/** Get benchmark use cycle */
|
||||
#define BENCH_GET_USECYC() (_bc_usecyc)
|
||||
|
||||
/** Get benchmark sum cycle */
|
||||
#define BENCH_GET_SUMCYC() (_bc_sumcyc)
|
||||
|
||||
/** Get benchmark loop count */
|
||||
#define BENCH_GET_LPCNT() (_bc_lpcnt)
|
||||
|
||||
/** Mark benchmark for proc is errored */
|
||||
#define BENCH_ERROR(proc) _bc_ercd = 1;
|
||||
/** Show the status of the benchmark */
|
||||
#define BENCH_STATUS(proc) if (_bc_ercd) { \
|
||||
printf("ERROR, %s\n", #proc); \
|
||||
} else { \
|
||||
printf("SUCCESS, %s\n", #proc); \
|
||||
}
|
||||
#else
|
||||
#define BENCH_DECLARE_VAR() static volatile unsigned long _bc_ercd, _bc_lpcnt;
|
||||
#define BENCH_INIT() _bc_ercd = 0; __prepare_bench_env();
|
||||
#define BENCH_RESET(proc)
|
||||
#define BENCH_START(proc) _bc_ercd = 0;
|
||||
#define BENCH_SAMPLE(proc) _bc_lpcnt += 1;
|
||||
#define BENCH_END(proc)
|
||||
#define BENCH_STOP(proc)
|
||||
#define BENCH_STAT(proc)
|
||||
#define BENCH_GET_USECYC() (0)
|
||||
#define BENCH_GET_SUMCYC() (0)
|
||||
#define BENCH_GET_LPCNT() (_bc_lpcnt)
|
||||
#define BENCH_ERROR(proc) _bc_ercd = 1;
|
||||
#define BENCH_STATUS(proc) if (_bc_ercd) { \
|
||||
printf("ERROR, %s\n", #proc); \
|
||||
} else { \
|
||||
printf("SUCCESS, %s\n", #proc); \
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
// High performance monitor bench helpers
|
||||
#if defined(__HPM_PRESENT) && (__HPM_PRESENT == 1) && (!defined(DISABLE_NMSIS_HPM))
|
||||
|
||||
/* Events type select */
|
||||
#define EVENT_SEL_INSTRUCTION_COMMIT 0
|
||||
#define EVENT_SEL_MEMORY_ACCESS 1
|
||||
#define EVENT_SEL_TYPE_0 0
|
||||
#define EVENT_SEL_TYPE_1 1
|
||||
/* The following event type 2 and 3 are introduced in PMU v2 */
|
||||
#define EVENT_SEL_TYPE_2 2
|
||||
#define EVENT_SEL_TYPE_3 3
|
||||
|
||||
/* Instruction commit events idx macros */
|
||||
#define EVENT_INSTRUCTION_COMMIT_CYCLE_COUNT 1
|
||||
#define EVENT_INSTRUCTION_COMMIT_RETIRED_COUNT 2
|
||||
/* Integer load instruction (includes LR) */
|
||||
#define EVENT_INSTRUCTION_COMMIT_INTEGER_LOAD 3
|
||||
/* Integer store instruction (includes SC) */
|
||||
#define EVENT_INSTRUCTION_COMMIT_INTEGER_STORE 4
|
||||
/* Atomic memory operation (do not include LR and SC) */
|
||||
#define EVENT_INSTRUCTION_COMMIT_ATOMIC_MEMORY_OPERATION 5
|
||||
/* System instruction */
|
||||
#define EVENT_INSTRUCTION_COMMIT_SYSTEM 6
|
||||
/* Integer computational instruction (excluding multiplication/division/remainder) */
|
||||
#define EVENT_INSTRUCTION_COMMIT_INTEGER_COMPUTATIONAL 7
|
||||
#define EVENT_INSTRUCTION_COMMIT_CONDITIONAL_BRANCH 8
|
||||
#define EVENT_INSTRUCTION_COMMIT_TAKEN_CONDITIONAL_BRANCH 9
|
||||
#define EVENT_INSTRUCTION_COMMIT_JAL 10
|
||||
#define EVENT_INSTRUCTION_COMMIT_JALR 11
|
||||
#define EVENT_INSTRUCTION_COMMIT_RETURN 12
|
||||
/* Control transfer instruction (CBR+JAL+JALR) */
|
||||
#define EVENT_INSTRUCTION_COMMIT_CONTROL_TRANSFER 13
|
||||
/* 14 fence instruction(Not include fence.i) */
|
||||
#define EVENT_INSTRUCTION_COMMIT_FENCE_INSTRUCTION 14
|
||||
#define EVENT_INSTRUCTION_COMMIT_INTEGER_MULTIPLICATION 15
|
||||
/* Integer division/remainder instruction */
|
||||
#define EVENT_INSTRUCTION_COMMIT_INTEGER_DIVISION_REMAINDER 16
|
||||
#define EVENT_INSTRUCTION_COMMIT_FLOATING_POINT_LOAD 17
|
||||
#define EVENT_INSTRUCTION_COMMIT_FLOATING_POINT_STORE 18
|
||||
/* Floating-point addition/subtraction */
|
||||
#define EVENT_INSTRUCTION_COMMIT_FLOATING_POINT_ADDITION_SUBTRACTION 19
|
||||
#define EVENT_INSTRUCTION_COMMIT_FLOATING_POINT_MULTIPLICATION 20
|
||||
/* Floating-point fused multiply-add (FMADD, FMSUB, FNMSUB, FNMADD) */
|
||||
#define EVENT_INSTRUCTION_COMMIT_FLOATING_POINT_FUSED_MULTIPLY_ADD_SUB 21
|
||||
#define EVENT_INSTRUCTION_COMMIT_FLOATING_POINT_DIVISION_OR_SQUARE_ROOT 22
|
||||
#define EVENT_INSTRUCTION_COMMIT_OTHER_FLOATING_POINT_INSTRUCTION 23
|
||||
#define EVENT_INSTRUCTION_COMMIT_CONDITIONAL_BRANCH_PREDICTION_FAIL 24
|
||||
/* JAL_PREDICTION_FAIL never existed, it is wrong documented, JALR_PREDICTION_FAIL should be 25 not 26 */
|
||||
#define EVENT_INSTRUCTION_COMMIT_JALR_PREDICTION_FAIL 25
|
||||
#define EVENT_INSTRUCTION_COMMIT_POP_PREDICTION_FAIL 26
|
||||
#define EVENT_INSTRUCTION_COMMIT_FENCEI_INSTRUCTION 27
|
||||
#define EVENT_INSTRUCTION_COMMIT_SFENCE_INSTRUCTION 28
|
||||
#define EVENT_INSTRUCTION_COMMIT_ECALL_INSTRUCTION 29
|
||||
#define EVENT_INSTRUCTION_COMMIT_EXCEPTION_INSTRUCTION 30
|
||||
#define EVENT_INSTRUCTION_COMMIT_INTERRUPT_INSTRUCTION 31
|
||||
|
||||
/* Memory access events idx macros */
|
||||
#define EVENT_MEMORY_ACCESS_ICACHE_MISS 1
|
||||
#define EVENT_MEMORY_ACCESS_DCACHE_MISS 2
|
||||
#define EVENT_MEMORY_ACCESS_ITLB_MISS 3
|
||||
#define EVENT_MEMORY_ACCESS_DTLB_MISS 4
|
||||
#define EVENT_MEMORY_ACCESS_MAIN_DTLB_MISS 5
|
||||
#define EVENT_MEMORY_ACCESS_MAIN_TLB_MISS 5
|
||||
/* The following events are introduced in PMU v2 */
|
||||
#define EVENT_MEMORY_ACCESS_L2_CACHE_ACCESS 8
|
||||
#define EVENT_MEMORY_ACCESS_L2_CACHE_MISS 9
|
||||
/* For Single Core, the Core memory bus read/write request count
|
||||
* For SMP Core, the cluster memory bus read/write/prefetch request count
|
||||
* is initiated by current Core */
|
||||
#define EVENT_MEMORY_ACCESS_MEMORY_BUS_REQUEST 10
|
||||
#define EVENT_MEMORY_ACCESS_IFU_STALL_CYCLE 11
|
||||
#define EVENT_MEMORY_ACCESS_EXU_STALL_CYCLE 12
|
||||
#define EVENT_MEMORY_ACCESS_TIMER 13
|
||||
|
||||
/*
|
||||
* Here are new event types macro naming for PMU v1 and v2.
|
||||
* Since the event type can be no longer summary into a group naming,
|
||||
* so we just use the event type id such as TYPE_0, TYPE_1, TYPE_2, TYPE_3
|
||||
*/
|
||||
/* Events Type 0 (event sel == 0) event name macros */
|
||||
#define EVENT_TYPE_0_CYCLE_COUNT 1
|
||||
#define EVENT_TYPE_0_RETIRED_COUNT 2
|
||||
#define EVENT_TYPE_0_INTEGER_LOAD 3
|
||||
#define EVENT_TYPE_0_INTEGER_STORE 4
|
||||
#define EVENT_TYPE_0_ATOMIC_MEMORY_OPERATION 5
|
||||
#define EVENT_TYPE_0_SYSTEM 6
|
||||
#define EVENT_TYPE_0_INTEGER_COMPUTATIONAL 7
|
||||
#define EVENT_TYPE_0_CONDITIONAL_BRANCH 8
|
||||
#define EVENT_TYPE_0_TAKEN_CONDITIONAL_BRANCH 9
|
||||
#define EVENT_TYPE_0_JAL 10
|
||||
#define EVENT_TYPE_0_JALR 11
|
||||
#define EVENT_TYPE_0_RETURN 12
|
||||
#define EVENT_TYPE_0_CONTROL_TRANSFER 13
|
||||
#define EVENT_TYPE_0_FENCE_INSTRUCTION 14
|
||||
#define EVENT_TYPE_0_INTEGER_MULTIPLICATION 15
|
||||
#define EVENT_TYPE_0_INTEGER_DIVISION_REMAINDER 16
|
||||
#define EVENT_TYPE_0_FLOATING_POINT_LOAD 17
|
||||
#define EVENT_TYPE_0_FLOATING_POINT_STORE 18
|
||||
#define EVENT_TYPE_0_FLOATING_POINT_ADDITION_SUBTRACTION 19
|
||||
#define EVENT_TYPE_0_FLOATING_POINT_MULTIPLICATION 20
|
||||
#define EVENT_TYPE_0_FLOATING_POINT_FUSED_MULTIPLY_ADD_SUB 21
|
||||
#define EVENT_TYPE_0_FLOATING_POINT_DIVISION_OR_SQUARE_ROOT 22
|
||||
#define EVENT_TYPE_0_OTHER_FLOATING_POINT_INSTRUCTION 23
|
||||
#define EVENT_TYPE_0_CONDITIONAL_BRANCH_PREDICTION_FAIL 24
|
||||
#define EVENT_TYPE_0_JALR_PREDICTION_FAIL 25
|
||||
#define EVENT_TYPE_0_POP_PREDICTION_FAIL 26
|
||||
#define EVENT_TYPE_0_FENCEI_INSTRUCTION 27
|
||||
#define EVENT_TYPE_0_SFENCE_INSTRUCTION 28
|
||||
#define EVENT_TYPE_0_ECALL_INSTRUCTION 29
|
||||
#define EVENT_TYPE_0_EXCEPTION_INSTRUCTION 30
|
||||
#define EVENT_TYPE_0_INTERRUPT_INSTRUCTION 31
|
||||
|
||||
/* Events Type 1 (event sel == 1) event name macros */
|
||||
#define EVENT_TYPE_1_ICACHE_READ_MISS 1
|
||||
#define EVENT_TYPE_1_DCACHE_RW_MISS 2
|
||||
#define EVENT_TYPE_1_ITLB_READ_MISS 3
|
||||
#define EVENT_TYPE_1_DTLB_RW_MISS 4
|
||||
#define EVENT_TYPE_1_MAIN_TLB_MISS 5
|
||||
#define EVENT_TYPE_1_L2_CACHE_ACCESS 8
|
||||
#define EVENT_TYPE_1_L2_CACHE_MISS 9
|
||||
#define EVENT_TYPE_1_MEMORY_BUS_REQUEST 10
|
||||
#define EVENT_TYPE_1_IFU_STALL_CYCLE 11
|
||||
#define EVENT_TYPE_1_EXU_STALL_CYCLE 12
|
||||
#define EVENT_TYPE_1_TIMER 13
|
||||
|
||||
/* Events Type 2 (event sel == 2) event name macros */
|
||||
#define EVENT_TYPE_2_BRANCH_INSTRUCTION_COMMIT 2
|
||||
#define EVENT_TYPE_2_BRANCH_PREDICT_FAIL_COMMIT 3
|
||||
|
||||
/* Events Type 3 (event sel == 3) event name macros */
|
||||
#define EVENT_TYPE_3_DCACHE_READ 0
|
||||
#define EVENT_TYPE_3_DCACHE_READ_MISS 1
|
||||
#define EVENT_TYPE_3_DCACHE_WRITE 2
|
||||
#define EVENT_TYPE_3_DCACHE_WRITE_MISS 3
|
||||
#define EVENT_TYPE_3_DCACHE_PREFETCH 4
|
||||
#define EVENT_TYPE_3_DCACHE_PREFETCH_MISS 5
|
||||
#define EVENT_TYPE_3_ICACHE_READ 6
|
||||
#define EVENT_TYPE_3_ICACHE_PREFETCH 8
|
||||
#define EVENT_TYPE_3_ICACHE_PREFETCH_MISS 9
|
||||
#define EVENT_TYPE_3_L2_CACHE_READ 10
|
||||
#define EVENT_TYPE_3_L2_CACHE_READ_MISS 11
|
||||
#define EVENT_TYPE_3_L2_CACHE_WRITE 12
|
||||
#define EVENT_TYPE_3_L2_CACHE_WRITE_MISS 13
|
||||
#define EVENT_TYPE_3_L2_CACHE_PREFETCH_HIT 14
|
||||
#define EVENT_TYPE_3_L2_CACHE_PREFETCH_MISS 15
|
||||
#define EVENT_TYPE_3_DTLB_READ 16
|
||||
#define EVENT_TYPE_3_DTLB_READ_MISS 17
|
||||
#define EVENT_TYPE_3_DTLB_WRITE 18
|
||||
#define EVENT_TYPE_3_DTLB_WRITE_MISS 19
|
||||
#define EVENT_TYPE_3_ITLB_READ 20
|
||||
#define EVENT_TYPE_3_BTB_READ 22
|
||||
#define EVENT_TYPE_3_BTB_READ_MISS 23
|
||||
#define EVENT_TYPE_3_BTB_WRITE 24
|
||||
#define EVENT_TYPE_3_BTB_WRITE_MISS 25
|
||||
|
||||
/* Enable the corresponding performance monitor counter increment for events in Machine/Supervisor/User Mode */
|
||||
#define MSU_EVENT_ENABLE 0x0F
|
||||
#define MEVENT_EN 0x08
|
||||
#define SEVENT_EN 0x02
|
||||
#define UEVENT_EN 0x01
|
||||
|
||||
#ifdef BENCH_XLEN_MODE
|
||||
/**
|
||||
* NOTE: when XLEN=32 and `BENCH_XLEN_MODE` is enabled, the counter should not exceed 2^32
|
||||
*/
|
||||
#define READ_HPM_COUNTER __read_hpm_counter
|
||||
#else
|
||||
#define READ_HPM_COUNTER __get_hpm_counter
|
||||
#endif /* #ifdef BENCH_XLEN_MODE */
|
||||
|
||||
/** Declare high performance monitor counter idx benchmark required variables, need to be placed above all HPM_xxx macros in each c source code if HPM_xxx used */
|
||||
#define HPM_DECLARE_VAR(idx) static volatile Bench_Type __hpm_sttcyc##idx, __hpm_endcyc##idx, __hpm_usecyc##idx, __hpm_sumcyc##idx; \
|
||||
static volatile unsigned long __hpm_lpcnt##idx, __hpm_val##idx;
|
||||
|
||||
#define HPM_SEL_ENABLE(ena) (ena << 28)
|
||||
#define HPM_SEL_EVENT(sel, idx) ((sel) | (idx << 4))
|
||||
|
||||
/** Construct a event variable to be set(sel -> event_sel, idx -> event_idx, ena -> m/s/u_enable) */
|
||||
#define HPM_EVENT(sel, idx, ena) (HPM_SEL_ENABLE(ena) | HPM_SEL_EVENT(sel, idx))
|
||||
|
||||
/** Initialize high performance monitor environment, need to called in before other HPM_xxx macros are called */
|
||||
#define HPM_INIT() printf("High performance monitor initialized\n"); \
|
||||
__prepare_bench_env();
|
||||
|
||||
/** Reset high performance benchmark for proc using counter which index is idx */
|
||||
#define HPM_RESET(idx, proc, event) __hpm_sumcyc##idx = 0; __hpm_lpcnt##idx = 0;
|
||||
|
||||
/** Start to do high performance benchmark for proc, and record start hpm counter */
|
||||
#define HPM_START(idx, proc, event) \
|
||||
__hpm_val##idx = (event); \
|
||||
__set_hpm_event(idx, __hpm_val##idx); \
|
||||
__set_hpm_counter(idx, 0); \
|
||||
__hpm_sttcyc##idx = READ_HPM_COUNTER(idx);
|
||||
|
||||
/** Do high performance benchmark sample for proc, and sum it into sum counter */
|
||||
#define HPM_SAMPLE(idx, proc, event) \
|
||||
__hpm_endcyc##idx = READ_HPM_COUNTER(idx); \
|
||||
__hpm_usecyc##idx = __hpm_endcyc##idx - __hpm_sttcyc##idx; \
|
||||
__hpm_sumcyc##idx += __hpm_usecyc##idx; \
|
||||
__hpm_lpcnt##idx += 1;
|
||||
|
||||
/** Mark end of high performance benchmark for proc, and calc used hpm counter value */
|
||||
#define HPM_END(idx, proc, event) \
|
||||
HPM_SAMPLE(idx, proc, event); \
|
||||
printf("HPM%d:0x%x, %s, %lu\n", idx, event, #proc, (unsigned long)__hpm_usecyc##idx);
|
||||
|
||||
/** Mark stop of hpm benchmark, start -> sample -> sample -> stop, and print the sum cycle of a proc */
|
||||
#define HPM_STOP(idx, proc, event) \
|
||||
printf("HPM%d:0x%x, %s, %lu\n", idx, event, #proc, (unsigned long)__hpm_sumcyc##idx);
|
||||
|
||||
/** Show statistics of hpm benchmark, format: STATHPM#idx:event, proc, loopcnt, sumcyc */
|
||||
#define HPM_STAT(idx, proc, event) \
|
||||
printf("STATHPM%d:0x%x, %s, %lu, %lu\n", idx, event, #proc, (unsigned long)__hpm_lpcnt##idx, (unsigned long)__hpm_sumcyc##idx);
|
||||
|
||||
/** Get hpm benchmark use cycle for counter idx */
|
||||
#define HPM_GET_USECYC(idx) (__hpm_usecyc##idx)
|
||||
|
||||
/** Get hpm benchmark sum cycle for counter idx */
|
||||
#define HPM_GET_SUMCYC(idx) (__hpm_sumcyc##idx)
|
||||
|
||||
/** Get hpm benchmark loop count for counter idx */
|
||||
#define HPM_GET_LPCNT(idx) (__hpm_lpcnt##idx)
|
||||
|
||||
#else
|
||||
#define HPM_DECLARE_VAR(idx)
|
||||
#define HPM_EVENT(sel, idx, ena)
|
||||
#define HPM_INIT()
|
||||
#define HPM_RESET(idx, proc, event)
|
||||
#define HPM_START(idx, proc, event)
|
||||
#define HPM_SAMPLE(idx, proc, event)
|
||||
#define HPM_END(idx, proc, event)
|
||||
#define HPM_STOP(idx, proc, event)
|
||||
#define HPM_STAT(idx, proc, event)
|
||||
#define HPM_GET_USECYC(idx) (0)
|
||||
#define HPM_GET_SUMCYC(idx) (0)
|
||||
#define HPM_GET_LPCNT(idx) (1)
|
||||
#endif
|
||||
|
||||
// NMSIS Helpers
|
||||
#ifndef DISABLE_NMSIS_HELPER
|
||||
/** Mark test or application passed */
|
||||
#define NMSIS_TEST_PASS() printf("\nNMSIS_TEST_PASS\n");
|
||||
/** Mark test or application failed */
|
||||
#define NMSIS_TEST_FAIL() printf("\nNMSIS_TEST_FAIL\n");
|
||||
#else
|
||||
#define NMSIS_TEST_PASS()
|
||||
#define NMSIS_TEST_FAIL()
|
||||
#endif
|
||||
|
||||
/** @} */ /* End of Doxygen Group NMSIS_Core_Bench_Helpers */
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif /* __NMSIS_BENCH__ */
|
||||
@@ -0,0 +1,105 @@
|
||||
/*
|
||||
* Copyright (c) 2019 Nuclei Limited. All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* 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 __NMSIS_COMPILER_H
|
||||
#define __NMSIS_COMPILER_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/*!
|
||||
* @file nmsis_compiler.h
|
||||
* @brief NMSIS compiler generic header file
|
||||
*/
|
||||
#if defined ( __GNUC__ )
|
||||
/* GNU GCC Compiler */
|
||||
#include "nmsis_gcc.h"
|
||||
#elif defined ( __ICCRISCV__ )
|
||||
/* IAR Compiler */
|
||||
#include "nmsis_iar.h"
|
||||
#else
|
||||
#error Unknown compiler.
|
||||
#endif
|
||||
|
||||
/* IO definitions (access restrictions to peripheral registers) */
|
||||
/**
|
||||
* \defgroup NMSIS_Core_PeriphAccess Peripheral Access
|
||||
* \brief Naming conventions and optional features for accessing peripherals.
|
||||
*
|
||||
* The section below describes the naming conventions, requirements, and optional features
|
||||
* for accessing device specific peripherals.
|
||||
* Most of the rules also apply to the core peripherals.
|
||||
*
|
||||
* The **Device Header File <device.h>** contains typically these definition
|
||||
* and also includes the core specific header files.
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
/** \brief Defines 'read only' permissions */
|
||||
#ifdef __cplusplus
|
||||
#define __I volatile
|
||||
#else
|
||||
#define __I volatile const
|
||||
#endif
|
||||
/** \brief Defines 'write only' permissions */
|
||||
#define __O volatile
|
||||
/** \brief Defines 'read / write' permissions */
|
||||
#define __IO volatile
|
||||
|
||||
/* following defines should be used for structure members */
|
||||
/** \brief Defines 'read only' structure member permissions */
|
||||
#define __IM volatile const
|
||||
/** \brief Defines 'write only' structure member permissions */
|
||||
#define __OM volatile
|
||||
/** \brief Defines 'read/write' structure member permissions */
|
||||
#define __IOM volatile
|
||||
|
||||
/**
|
||||
* \brief Mask and shift a bit field value for use in a register bit range.
|
||||
* \details The macro \ref _VAL2FLD uses the #define's _Pos and _Msk of the related bit
|
||||
* field to shift bit-field values for assigning to a register.
|
||||
*
|
||||
* **Example**:
|
||||
* \code
|
||||
* ECLIC->CFG = _VAL2FLD(CLIC_CLICCFG_NLBIT, 3);
|
||||
* \endcode
|
||||
* \param[in] field Name of the register bit field.
|
||||
* \param[in] value Value of the bit field. This parameter is interpreted as an uint32_t type.
|
||||
* \return Masked and shifted value.
|
||||
*/
|
||||
#define _VAL2FLD(field, value) (((uint32_t)(value) << field ## _Pos) & field ## _Msk)
|
||||
|
||||
/**
|
||||
* \brief Mask and shift a register value to extract a bit filed value.
|
||||
* \details The macro \ref _FLD2VAL uses the #define's _Pos and _Msk of the related bit
|
||||
* field to extract the value of a bit field from a register.
|
||||
*
|
||||
* **Example**:
|
||||
* \code
|
||||
* nlbits = _FLD2VAL(CLIC_CLICCFG_NLBIT, ECLIC->CFG);
|
||||
* \endcode
|
||||
* \param[in] field Name of the register bit field.
|
||||
* \param[in] value Value of register. This parameter is interpreted as an uint32_t type.
|
||||
* \return Masked and shifted bit field value.
|
||||
*/
|
||||
#define _FLD2VAL(field, value) (((uint32_t)(value) & field ## _Msk) >> field ## _Pos)
|
||||
|
||||
/** @} */ /* end of group NMSIS_Core_PeriphAccess */
|
||||
|
||||
|
||||
#endif /* __NMSIS_COMPILER_H */
|
||||
|
||||
@@ -0,0 +1,118 @@
|
||||
/*
|
||||
* Copyright (c) 2009-2019 Arm Limited. All rights reserved.
|
||||
* -- Adaptable modifications made for Nuclei Processors. --
|
||||
* Copyright (c) 2019 Nuclei Limited. All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* 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>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "nmsis_version.h"
|
||||
|
||||
/**
|
||||
* \ingroup NMSIS_Core_VersionControl
|
||||
* @{
|
||||
*/
|
||||
/* The following macro __NUCLEI_N_REV/__NUCLEI_NX_REV/
|
||||
* __NUCLEI_CPU_REV/__NUCLEI_CPU_SERIES definition in this file
|
||||
* is only used for doxygen documentation generation,
|
||||
* The <Device>.h is the real file to define it by vendor
|
||||
*/
|
||||
#if defined(__ONLY_FOR_DOXYGEN_DOCUMENT_GENERATION__)
|
||||
/**
|
||||
* \brief Nuclei N class core revision number
|
||||
* \details
|
||||
* Reversion number format: [15:8] revision number, [7:0] patch number
|
||||
* \attention
|
||||
* Deprecated, this define is exclusive with \ref __NUCLEI_NX_REV
|
||||
*/
|
||||
#define __NUCLEI_N_REV (0x0309)
|
||||
/**
|
||||
* \brief Nuclei NX class core revision number
|
||||
* \details
|
||||
* Reversion number format: [15:8] revision number, [7:0] patch number
|
||||
* \attention
|
||||
* Deprecated, this define is exclusive with \ref __NUCLEI_N_REV
|
||||
*/
|
||||
#define __NUCLEI_NX_REV (0x0207)
|
||||
/**
|
||||
* \brief Nuclei CPU core revision number
|
||||
* \details
|
||||
* Nuclei RISC-V CPU Revision Number vX.Y.Z, eg. v3.10.1
|
||||
* \attention
|
||||
* This define is exclusive with \ref __NUCLEI_CPU_SERIES
|
||||
*/
|
||||
#define __NUCLEI_CPU_REV (0x030A01)
|
||||
/**
|
||||
* \brief Nuclei CPU core series
|
||||
* \details
|
||||
* Nuclei RISC-V CPU Series Number, eg, 0x200, 0x300, 0x600, 0x900
|
||||
* for 200, 300, 600, 900 series.
|
||||
* \attention
|
||||
* This define is used together with \ref __NUCLEI_CPU_REV
|
||||
*/
|
||||
#define __NUCLEI_CPU_SERIES (0x0200)
|
||||
#endif /* __ONLY_FOR_DOXYGEN_DOCUMENT_GENERATION__ */
|
||||
/** @} */ /* End of Group NMSIS_Core_VersionControl */
|
||||
|
||||
#include "nmsis_compiler.h" /* NMSIS compiler specific defines */
|
||||
|
||||
/* === Include Nuclei Core Related Headers === */
|
||||
/* Include core base feature header file */
|
||||
#include "core_feature_base.h"
|
||||
|
||||
/* Include core fpu feature header file */
|
||||
#include "core_feature_fpu.h"
|
||||
/* Include core dsp feature header file */
|
||||
#include "core_feature_dsp.h"
|
||||
/* Include core vector feature header file */
|
||||
#include "core_feature_vector.h"
|
||||
/* Include core bitmanip feature header file */
|
||||
#include "core_feature_bitmanip.h"
|
||||
/* Include core pmp feature header file */
|
||||
#include "core_feature_pmp.h"
|
||||
/* Include core spmp feature header file */
|
||||
#include "core_feature_spmp.h"
|
||||
/* Include core cache feature header file */
|
||||
#include "core_feature_cache.h"
|
||||
/* Include core cidu feature header file */
|
||||
#include "core_feature_cidu.h"
|
||||
/* Include core pma feature header file */
|
||||
#include "core_feature_pma.h"
|
||||
/* Include core smpcc feature header file */
|
||||
#include "core_feature_smpcc.h"
|
||||
/* Include core ecc feature header file */
|
||||
#include "core_feature_ecc.h"
|
||||
/* Include core iregion info header file */
|
||||
#include "core_feature_iinfo.h"
|
||||
/* Include compatiable functions header file */
|
||||
#include "core_compatiable.h"
|
||||
|
||||
#ifndef __NMSIS_GENERIC
|
||||
/* Include core eclic feature header file */
|
||||
#include "core_feature_eclic.h"
|
||||
/* Include core plic feature header file */
|
||||
#include "core_feature_plic.h"
|
||||
/* Include core systimer feature header file */
|
||||
#include "core_feature_timer.h"
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,210 @@
|
||||
/*
|
||||
* Copyright (c) 2019 Nuclei Limited. All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* 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 __NMSIS_GCC_H__
|
||||
#define __NMSIS_GCC_H__
|
||||
/*!
|
||||
* @file nmsis_gcc.h
|
||||
* @brief NMSIS compiler GCC header file
|
||||
*/
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "riscv_encoding.h"
|
||||
|
||||
/* ######################### Startup and Lowlevel Init ######################## */
|
||||
/**
|
||||
* \defgroup NMSIS_Core_CompilerControl Compiler Control
|
||||
* \ingroup NMSIS_Core
|
||||
* \brief Compiler agnostic \#define symbols for generic c/c++ source code
|
||||
* \details
|
||||
*
|
||||
* The NMSIS-Core provides the header file <b>nmsis_compiler.h</b> with consistent \#define symbols for generate C or C++ source files that should be compiler agnostic.
|
||||
* Each NMSIS compliant compiler should support the functionality described in this section.
|
||||
*
|
||||
* The header file <b>nmsis_compiler.h</b> is also included by each Device Header File <device.h> so that these definitions are available.
|
||||
* @{
|
||||
*/
|
||||
|
||||
/* Fallback for __has_builtin */
|
||||
#ifndef __has_builtin
|
||||
#define __has_builtin(x) (0)
|
||||
#endif
|
||||
|
||||
/* NMSIS compiler specific defines */
|
||||
/** \brief Pass information from the compiler to the assembler. */
|
||||
#ifndef __ASM
|
||||
#define __ASM __asm
|
||||
#endif
|
||||
|
||||
/** \brief Recommend that function should be inlined by the compiler. */
|
||||
#ifndef __INLINE
|
||||
#define __INLINE inline
|
||||
#endif
|
||||
|
||||
/** \brief Define a static function that may be inlined by the compiler. */
|
||||
#ifndef __STATIC_INLINE
|
||||
#define __STATIC_INLINE static inline
|
||||
#endif
|
||||
|
||||
/** \brief Define a static function that should be always inlined by the compiler. */
|
||||
#ifndef __STATIC_FORCEINLINE
|
||||
#define __STATIC_FORCEINLINE __attribute__((always_inline)) static inline
|
||||
#endif
|
||||
|
||||
/** \brief Inform the compiler that a function does not return. */
|
||||
#ifndef __NO_RETURN
|
||||
#define __NO_RETURN __attribute__((__noreturn__))
|
||||
#endif
|
||||
|
||||
/** \brief Inform that a variable shall be retained in executable image. */
|
||||
#ifndef __USED
|
||||
#define __USED __attribute__((used))
|
||||
#endif
|
||||
|
||||
/** \brief restrict pointer qualifier to enable additional optimizations. */
|
||||
#ifndef __WEAK
|
||||
#define __WEAK __attribute__((weak))
|
||||
#endif
|
||||
|
||||
/** \brief specified the vector size of the variable, measured in bytes */
|
||||
#ifndef __VECTOR_SIZE
|
||||
#define __VECTOR_SIZE(x) __attribute__((vector_size(x)))
|
||||
#endif
|
||||
|
||||
/** \brief Request smallest possible alignment. */
|
||||
#ifndef __PACKED
|
||||
#define __PACKED __attribute__((packed, aligned(1)))
|
||||
#endif
|
||||
|
||||
/** \brief Request smallest possible alignment for a structure. */
|
||||
#ifndef __PACKED_STRUCT
|
||||
#define __PACKED_STRUCT struct __attribute__((packed, aligned(1)))
|
||||
#endif
|
||||
|
||||
/** \brief Request smallest possible alignment for a union. */
|
||||
#ifndef __PACKED_UNION
|
||||
#define __PACKED_UNION union __attribute__((packed, aligned(1)))
|
||||
#endif
|
||||
|
||||
#ifndef __UNALIGNED_UINT16_WRITE
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wpacked"
|
||||
#pragma GCC diagnostic ignored "-Wattributes"
|
||||
/** \brief Packed struct for unaligned uint16_t write access */
|
||||
__PACKED_STRUCT T_UINT16_WRITE {
|
||||
uint16_t v;
|
||||
};
|
||||
#pragma GCC diagnostic pop
|
||||
/** \brief Pointer for unaligned write of a uint16_t variable. */
|
||||
#define __UNALIGNED_UINT16_WRITE(addr, val) (void)((((struct T_UINT16_WRITE *)(void *)(addr))->v) = (val))
|
||||
#endif
|
||||
|
||||
#ifndef __UNALIGNED_UINT16_READ
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wpacked"
|
||||
#pragma GCC diagnostic ignored "-Wattributes"
|
||||
/** \brief Packed struct for unaligned uint16_t read access */
|
||||
__PACKED_STRUCT T_UINT16_READ {
|
||||
uint16_t v;
|
||||
};
|
||||
#pragma GCC diagnostic pop
|
||||
/** \brief Pointer for unaligned read of a uint16_t variable. */
|
||||
#define __UNALIGNED_UINT16_READ(addr) (((const struct T_UINT16_READ *)(const void *)(addr))->v)
|
||||
#endif
|
||||
|
||||
#ifndef __UNALIGNED_UINT32_WRITE
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wpacked"
|
||||
#pragma GCC diagnostic ignored "-Wattributes"
|
||||
/** \brief Packed struct for unaligned uint32_t write access */
|
||||
__PACKED_STRUCT T_UINT32_WRITE {
|
||||
uint32_t v;
|
||||
};
|
||||
#pragma GCC diagnostic pop
|
||||
/** \brief Pointer for unaligned write of a uint32_t variable. */
|
||||
#define __UNALIGNED_UINT32_WRITE(addr, val) (void)((((struct T_UINT32_WRITE *)(void *)(addr))->v) = (val))
|
||||
#endif
|
||||
|
||||
#ifndef __UNALIGNED_UINT32_READ
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wpacked"
|
||||
#pragma GCC diagnostic ignored "-Wattributes"
|
||||
/** \brief Packed struct for unaligned uint32_t read access */
|
||||
__PACKED_STRUCT T_UINT32_READ {
|
||||
uint32_t v;
|
||||
};
|
||||
#pragma GCC diagnostic pop
|
||||
/** \brief Pointer for unaligned read of a uint32_t variable. */
|
||||
#define __UNALIGNED_UINT32_READ(addr) (((const struct T_UINT32_READ *)(const void *)(addr))->v)
|
||||
#endif
|
||||
|
||||
/** \brief Minimum `x` bytes alignment for a variable. */
|
||||
#ifndef __ALIGNED
|
||||
#define __ALIGNED(x) __attribute__((aligned(x)))
|
||||
#endif
|
||||
|
||||
/** \brief restrict pointer qualifier to enable additional optimizations. */
|
||||
#ifndef __RESTRICT
|
||||
#define __RESTRICT __restrict
|
||||
#endif
|
||||
|
||||
/** \brief Barrier to prevent compiler from reordering instructions. */
|
||||
#ifndef __COMPILER_BARRIER
|
||||
#define __COMPILER_BARRIER() __ASM volatile("":::"memory")
|
||||
#endif
|
||||
|
||||
/** \brief provide the compiler with branch prediction information, the branch is usually true */
|
||||
#ifndef __USUALLY
|
||||
#define __USUALLY(exp) __builtin_expect((exp), 1)
|
||||
#endif
|
||||
|
||||
/** \brief provide the compiler with branch prediction information, the branch is rarely true */
|
||||
#ifndef __RARELY
|
||||
#define __RARELY(exp) __builtin_expect((exp), 0)
|
||||
#endif
|
||||
|
||||
/** \brief Use this attribute to indicate that the specified function is an interrupt handler run in Machine Mode. */
|
||||
#ifndef __INTERRUPT
|
||||
#define __INTERRUPT __attribute__((interrupt))
|
||||
#endif
|
||||
|
||||
/** \brief Use this attribute to indicate that the specified function is an interrupt handler run in Machine Mode. */
|
||||
#ifndef __MACHINE_INTERRUPT
|
||||
#define __MACHINE_INTERRUPT __attribute__ ((interrupt ("machine")))
|
||||
#endif
|
||||
|
||||
/** \brief Use this attribute to indicate that the specified function is an interrupt handler run in Supervisor Mode. */
|
||||
#ifndef __SUPERVISOR_INTERRUPT
|
||||
#define __SUPERVISOR_INTERRUPT __attribute__ ((interrupt ("supervisor")))
|
||||
#endif
|
||||
|
||||
/** \brief Use this attribute to indicate that the specified function is an interrupt handler run in User Mode. */
|
||||
#ifndef __USER_INTERRUPT
|
||||
#define __USER_INTERRUPT __attribute__ ((interrupt ("user")))
|
||||
#endif
|
||||
|
||||
/** @} */ /* End of Doxygen Group NMSIS_Core_CompilerControl */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif /* __NMSIS_GCC_H__ */
|
||||
@@ -0,0 +1,206 @@
|
||||
/*
|
||||
* Copyright (c) 2019 Nuclei Limited. All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* 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 __NMSIS_IAR_H__
|
||||
#define __NMSIS_IAR_H__
|
||||
/*!
|
||||
* @file nmsis_iar.h
|
||||
* @brief NMSIS compiler IAR header file
|
||||
*/
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "riscv_encoding.h"
|
||||
|
||||
/* ######################### Startup and Lowlevel Init ######################## */
|
||||
/**
|
||||
* \defgroup NMSIS_Core_CompilerControl Compiler Control
|
||||
* \ingroup NMSIS_Core
|
||||
* \brief Compiler agnostic \#define symbols for generic c/c++ source code
|
||||
* \details
|
||||
*
|
||||
* The NMSIS-Core provides the header file <b>nmsis_compiler.h</b> with consistent \#define symbols for generate C or C++ source files that should be compiler agnostic.
|
||||
* Each NMSIS compliant compiler should support the functionality described in this section.
|
||||
*
|
||||
* The header file <b>nmsis_compiler.h</b> is also included by each Device Header File <device.h> so that these definitions are available.
|
||||
* @{
|
||||
*/
|
||||
|
||||
/* Fallback for __has_builtin */
|
||||
#ifndef __has_builtin
|
||||
#define __has_builtin(x) (0)
|
||||
#endif
|
||||
|
||||
/* NMSIS compiler specific defines */
|
||||
/** \brief Pass information from the compiler to the assembler. */
|
||||
#ifndef __ASM
|
||||
#define __ASM __asm
|
||||
#endif
|
||||
|
||||
/** \brief Recommend that function should be inlined by the compiler. */
|
||||
#ifndef __INLINE
|
||||
#define __INLINE inline
|
||||
#endif
|
||||
|
||||
/** \brief Define a static function that may be inlined by the compiler. */
|
||||
#ifndef __STATIC_INLINE
|
||||
#define __STATIC_INLINE static inline
|
||||
#endif
|
||||
|
||||
/** \brief Define a static function that should be always inlined by the compiler. */
|
||||
#ifndef __STATIC_FORCEINLINE
|
||||
#define __STATIC_FORCEINLINE __attribute__((always_inline)) static inline
|
||||
#endif
|
||||
|
||||
/** \brief Inform the compiler that a function does not return. */
|
||||
#ifndef __NO_RETURN
|
||||
#define __NO_RETURN __attribute__((__noreturn__))
|
||||
#endif
|
||||
|
||||
/** \brief Inform that a variable shall be retained in executable image. */
|
||||
#ifndef __USED
|
||||
#define __USED __attribute__((used))
|
||||
#endif
|
||||
|
||||
/** \brief restrict pointer qualifier to enable additional optimizations. */
|
||||
#ifndef __WEAK
|
||||
#define __WEAK __attribute__((weak))
|
||||
#endif
|
||||
|
||||
/** \brief specified the vector size of the variable, measured in bytes, not supported in IAR */
|
||||
#ifndef __VECTOR_SIZE
|
||||
#define __VECTOR_SIZE(x)
|
||||
#endif
|
||||
|
||||
/** \brief Request smallest possible alignment. */
|
||||
#ifndef __PACKED
|
||||
#define __PACKED __attribute__((packed, aligned(1)))
|
||||
#endif
|
||||
|
||||
/** \brief Request smallest possible alignment for a structure. */
|
||||
#ifndef __PACKED_STRUCT
|
||||
#define __PACKED_STRUCT struct __attribute__((packed, aligned(1)))
|
||||
#endif
|
||||
|
||||
/** \brief Request smallest possible alignment for a union. */
|
||||
#ifndef __PACKED_UNION
|
||||
#define __PACKED_UNION union __attribute__((packed, aligned(1)))
|
||||
#endif
|
||||
|
||||
#ifndef __UNALIGNED_UINT16_WRITE
|
||||
#pragma language=save
|
||||
#pragma language=extended
|
||||
/** \brief Packed struct for unaligned uint16_t write access */
|
||||
__PACKED_STRUCT T_UINT16_WRITE {
|
||||
uint16_t v;
|
||||
};
|
||||
#pragma language=restore
|
||||
/** \brief Pointer for unaligned write of a uint16_t variable. */
|
||||
#define __UNALIGNED_UINT16_WRITE(addr, val) (void)((((struct T_UINT16_WRITE *)(void *)(addr))->v) = (val))
|
||||
#endif
|
||||
|
||||
#ifndef __UNALIGNED_UINT16_READ
|
||||
#pragma language=save
|
||||
#pragma language=extended
|
||||
/** \brief Packed struct for unaligned uint16_t read access */
|
||||
__PACKED_STRUCT T_UINT16_READ {
|
||||
uint16_t v;
|
||||
};
|
||||
#pragma language=restore
|
||||
/** \brief Pointer for unaligned read of a uint16_t variable. */
|
||||
#define __UNALIGNED_UINT16_READ(addr) (((const struct T_UINT16_READ *)(const void *)(addr))->v)
|
||||
#endif
|
||||
|
||||
#ifndef __UNALIGNED_UINT32_WRITE
|
||||
#pragma language=save
|
||||
#pragma language=extended
|
||||
/** \brief Packed struct for unaligned uint32_t write access */
|
||||
__PACKED_STRUCT T_UINT32_WRITE {
|
||||
uint32_t v;
|
||||
};
|
||||
#pragma language=restore
|
||||
/** \brief Pointer for unaligned write of a uint32_t variable. */
|
||||
#define __UNALIGNED_UINT32_WRITE(addr, val) (void)((((struct T_UINT32_WRITE *)(void *)(addr))->v) = (val))
|
||||
#endif
|
||||
|
||||
#ifndef __UNALIGNED_UINT32_READ
|
||||
#pragma language=save
|
||||
#pragma language=extended
|
||||
/** \brief Packed struct for unaligned uint32_t read access */
|
||||
__PACKED_STRUCT T_UINT32_READ {
|
||||
uint32_t v;
|
||||
};
|
||||
#pragma language=restore
|
||||
/** \brief Pointer for unaligned read of a uint32_t variable. */
|
||||
#define __UNALIGNED_UINT32_READ(addr) (((const struct T_UINT32_READ *)(const void *)(addr))->v)
|
||||
#endif
|
||||
|
||||
/** \brief Minimum `x` bytes alignment for a variable. */
|
||||
#ifndef __ALIGNED
|
||||
#define __ALIGNED(x) __attribute__((aligned(x)))
|
||||
#endif
|
||||
|
||||
/** \brief restrict pointer qualifier to enable additional optimizations. */
|
||||
#ifndef __RESTRICT
|
||||
#define __RESTRICT __restrict
|
||||
#endif
|
||||
|
||||
/** \brief Barrier to prevent compiler from reordering instructions. */
|
||||
#ifndef __COMPILER_BARRIER
|
||||
#define __COMPILER_BARRIER() __ASM volatile("":::"memory")
|
||||
#endif
|
||||
|
||||
/** \brief provide the compiler with branch prediction information, the branch is usually true */
|
||||
#ifndef __USUALLY
|
||||
#define __USUALLY(exp) (exp)
|
||||
#endif
|
||||
|
||||
/** \brief provide the compiler with branch prediction information, the branch is rarely true */
|
||||
#ifndef __RARELY
|
||||
#define __RARELY(exp) (exp)
|
||||
#endif
|
||||
|
||||
/** \brief Use this attribute to indicate that the specified function is an interrupt handler run in Machine Mode. */
|
||||
#ifndef __INTERRUPT
|
||||
#define __INTERRUPT __machine __interrupt
|
||||
#endif
|
||||
|
||||
/** \brief Use this attribute to indicate that the specified function is an interrupt handler run in Machine Mode. */
|
||||
#ifndef __MACHINE_INTERRUPT
|
||||
#define __MACHINE_INTERRUPT __machine __interrupt
|
||||
#endif
|
||||
|
||||
/** \brief Use this attribute to indicate that the specified function is an interrupt handler run in Supervisor Mode. */
|
||||
#ifndef __SUPERVISOR_INTERRUPT
|
||||
#define __SUPERVISOR_INTERRUPT __supervisor __interrupt
|
||||
#endif
|
||||
|
||||
/** \brief Use this attribute to indicate that the specified function is an interrupt handler run in User Mode. */
|
||||
#ifndef __USER_INTERRUPT
|
||||
#define __USER_INTERRUPT __user __interrupt
|
||||
#endif
|
||||
|
||||
/** @} */ /* End of Doxygen Group NMSIS_Core_CompilerControl */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif /* __NMSIS_GCC_H__ */
|
||||
@@ -0,0 +1,87 @@
|
||||
/*
|
||||
* Copyright (c) 2019 Nuclei Limited. All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* 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 __NMSIS_VERSION_H
|
||||
#define __NMSIS_VERSION_H
|
||||
|
||||
/**
|
||||
* \defgroup NMSIS_Core_VersionControl Version Control
|
||||
* \ingroup NMSIS_Core
|
||||
* \brief Version \#define symbols for NMSIS release specific C/C++ source code
|
||||
* \details
|
||||
*
|
||||
* We followed the [semantic versioning 2.0.0](https://semver.org/) to control NMSIS version.
|
||||
* The version format is **MAJOR.MINOR.PATCH**, increment the:
|
||||
* 1. MAJOR version when you make incompatible API changes,
|
||||
* 2. MINOR version when you add functionality in a backwards compatible manner, and
|
||||
* 3. PATCH version when you make backwards compatible bug fixes.
|
||||
*
|
||||
* The header file `nmsis_version.h` is included by each core header so that these definitions are available.
|
||||
*
|
||||
* **Example Usage for NMSIS Version Check**:
|
||||
* \code
|
||||
* #if defined(__NMSIS_VERSION) && (__NMSIS_VERSION >= 0x00010105)
|
||||
* #warning "Yes, we have NMSIS 1.1.5 or later"
|
||||
* #else
|
||||
* #error "We need NMSIS 1.1.5 or later!"
|
||||
* #endif
|
||||
* \endcode
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
|
||||
/*!
|
||||
* \file nmsis_version.h
|
||||
* \brief NMSIS Version definitions
|
||||
**/
|
||||
|
||||
/**
|
||||
* \brief Represent the NMSIS major version
|
||||
* \details
|
||||
* The NMSIS major version can be used to
|
||||
* differentiate between NMSIS major releases.
|
||||
* */
|
||||
#define __NMSIS_VERSION_MAJOR (1U)
|
||||
|
||||
/**
|
||||
* \brief Represent the NMSIS minor version
|
||||
* \details
|
||||
* The NMSIS minor version can be used to
|
||||
* query a NMSIS release update including new features.
|
||||
*
|
||||
**/
|
||||
#define __NMSIS_VERSION_MINOR (6U)
|
||||
|
||||
/**
|
||||
* \brief Represent the NMSIS patch version
|
||||
* \details
|
||||
* The NMSIS patch version can be used to
|
||||
* show bug fixes in this package.
|
||||
**/
|
||||
#define __NMSIS_VERSION_PATCH (0U)
|
||||
/**
|
||||
* \brief Represent the NMSIS Version
|
||||
* \details
|
||||
* NMSIS Version format: **MAJOR.MINOR.PATCH**
|
||||
* * MAJOR: \ref __NMSIS_VERSION_MAJOR, stored in `bits [31:16]` of \ref __NMSIS_VERSION
|
||||
* * MINOR: \ref __NMSIS_VERSION_MINOR, stored in `bits [15:8]` of \ref __NMSIS_VERSION
|
||||
* * PATCH: \ref __NMSIS_VERSION_PATCH, stored in `bits [7:0]` of \ref __NMSIS_VERSION
|
||||
**/
|
||||
#define __NMSIS_VERSION ((__NMSIS_VERSION_MAJOR << 16U) | (__NMSIS_VERSION_MINOR << 8) | __NMSIS_VERSION_PATCH)
|
||||
|
||||
/** @} */ /* End of Doxygen Group NMSIS_Core_VersionControl */
|
||||
#endif
|
||||
@@ -0,0 +1,99 @@
|
||||
/*
|
||||
* Copyright (c) 2019 Nuclei Limited. All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* 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 __RISCV_BITS_H__
|
||||
#define __RISCV_BITS_H__
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#if __riscv_xlen == 64
|
||||
# define SLL32 sllw
|
||||
# define STORE sd
|
||||
# define LOAD ld
|
||||
# define LWU lwu
|
||||
# define LOG_REGBYTES 3
|
||||
#else
|
||||
# define SLL32 sll
|
||||
# define STORE sw
|
||||
# define LOAD lw
|
||||
# define LWU lw
|
||||
# define LOG_REGBYTES 2
|
||||
#endif /* __riscv_xlen */
|
||||
|
||||
#define REGBYTES (1 << LOG_REGBYTES)
|
||||
|
||||
#if defined(__riscv_flen)
|
||||
#if __riscv_flen == 64
|
||||
# define FPSTORE fsd
|
||||
# define FPLOAD fld
|
||||
# define LOG_FPREGBYTES 3
|
||||
#else
|
||||
# define FPSTORE fsw
|
||||
# define FPLOAD flw
|
||||
# define LOG_FPREGBYTES 2
|
||||
#endif /* __riscv_flen == 64 */
|
||||
#define FPREGBYTES (1 << LOG_FPREGBYTES)
|
||||
#endif /* __riscv_flen */
|
||||
|
||||
#ifdef __GNUC__
|
||||
#define __rv_likely(x) __builtin_expect((x), 1)
|
||||
#define __rv_unlikely(x) __builtin_expect((x), 0)
|
||||
#else
|
||||
#define __rv_likely(x) (x)
|
||||
#define __rv_unlikely(x) (x)
|
||||
#endif
|
||||
|
||||
#define __RV_ROUNDUP(a, b) ((((a)-1)/(b)+1)*(b))
|
||||
#define __RV_ROUNDDOWN(a, b) ((a)/(b)*(b))
|
||||
|
||||
#define __RV_MAX(a, b) ((a) > (b) ? (a) : (b))
|
||||
#define __RV_MIN(a, b) ((a) < (b) ? (a) : (b))
|
||||
#define __RV_CLAMP(a, lo, hi) __RV_MIN(__RV_MAX(a, lo), hi)
|
||||
|
||||
#define __RV_EXTRACT_FIELD(val, which) (((val) & (which)) / ((which) & ~((which)-1)))
|
||||
#define __RV_INSERT_FIELD(val, which, fieldval) (((val) & ~(which)) | ((fieldval) * ((which) & ~((which)-1))))
|
||||
|
||||
#ifdef __ASSEMBLER__
|
||||
#define _AC(X,Y) X
|
||||
#define _AT(T,X) X
|
||||
#else
|
||||
#define __AC(X,Y) (X##Y)
|
||||
#define _AC(X,Y) __AC(X,Y)
|
||||
#define _AT(T,X) ((T)(X))
|
||||
#endif /* __ASSEMBLER__ */
|
||||
|
||||
#define _UL(x) (_AC(x, UL))
|
||||
#define _ULL(x) (_AC(x, ULL))
|
||||
|
||||
#define _BITUL(x) (_UL(1) << (x))
|
||||
#define _BITULL(x) (_ULL(1) << (x))
|
||||
|
||||
#define UL(x) (_UL(x))
|
||||
#define ULL(x) (_ULL(x))
|
||||
|
||||
#define STR(x) XSTR(x)
|
||||
#define XSTR(x) #x
|
||||
#define __STR(s) #s
|
||||
#define STRINGIFY(s) __STR(s)
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __RISCV_BITS_H__ */
|
||||
File diff suppressed because it is too large.
Load diff
Reference in new issue
Block a user