| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922 |
- /*
- * 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_ECLIC__
- #define __CORE_FEATURE_ECLIC__
- /*!
- * @file core_feature_eclic.h
- * @brief ECLIC feature API header file for Nuclei N/NX Core
- */
- /*
- * ECLIC Feature Configuration Macro:
- * 1. __ECLIC_PRESENT: Define whether Enhanced Core Local Interrupt Controller (ECLIC) Unit is present or not
- * * 0: Not present
- * * 1: Present
- * 2. __ECLIC_BASEADDR: Base address of the ECLIC unit.
- * 3. __ECLIC_INTCTLBITS: Optional, if defined, it should set to the value of ECLIC_GetInfoCtlbits(), define the number of hardware bits are actually implemented in the clicintctl registers.
- * Valid number is 1 - 8.
- * 4. __ECLIC_INTNUM: Define the external interrupt number of ECLIC Unit
- * 5. __TEE_PRESENT: Define whether TEE feature present, if present, ECLIC will present with S-Mode ECLIC feature
- * * 0: Not present
- * * 1: Present
- *
- */
- #ifdef __cplusplus
- extern "C" {
- #endif
- #include "core_feature_base.h"
- #if defined(__ECLIC_PRESENT) && (__ECLIC_PRESENT == 1)
- /**
- * \defgroup NMSIS_Core_ECLIC_Registers Register Define and Type Definitions Of ECLIC
- * \ingroup NMSIS_Core_Registers
- * \brief Type definitions and defines for eclic registers.
- *
- * @{
- */
- /**
- * \brief Union type to access CLICFG configure register.
- */
- typedef union
- {
- struct {
- __IM uint8_t _reserved0:1;
- __IOM uint8_t nlbits:4; /*!< bit: 1..4 specified the bit-width of level and priority in the register clicintctl[i] */
- __IM uint8_t nmbits:2; /*!< bit: 5..6 ties to 1 if supervisor-level interrupt supported, or else it's reserved */
- __IM uint8_t _reserved1:1;
- } b; /*!< Structure used for bit access */
- uint8_t w; /*!< Type used for byte access */
- } CLICCFG_Type;
- /**
- * \brief Union type to access CLICINFO information register.
- */
- typedef union {
- struct {
- __IM uint32_t numint:13; /*!< bit: 0..12 number of maximum interrupt inputs supported */
- __IM uint32_t version:8; /*!< bit: 13..20 Hardware implementation version number. 1: version 1. 2: version 2, support hardware context saving and restoring. */
- __IM uint32_t intctlbits:4; /*!< bit: 21..24 specifies how many hardware bits are actually implemented in the clicintctl registers */
- __IM uint32_t shd_num:4; /*!< bit: 25..28 number of shadow register groups for single mode(M/S mode) */
- __IM uint32_t _reserved0:3; /*!< bit: 29..31 Reserved */
- } b; /*!< Structure used for bit access */
- __IM uint32_t w; /*!< Type used for word access */
- } CLICINFO_Type;
- /**
- * \brief Access to the machine mode register structure of INTIP, INTIE, INTATTR, INTCTL.
- */
- typedef struct {
- __IOM uint8_t INTIP; /*!< Offset: 0x000 (R/W) Interrupt set pending register */
- __IOM uint8_t INTIE; /*!< Offset: 0x001 (R/W) Interrupt set enable register */
- __IOM uint8_t INTATTR; /*!< Offset: 0x002 (R/W) Interrupt set attributes register */
- __IOM uint8_t INTCTRL; /*!< Offset: 0x003 (R/W) Interrupt configure register */
- } CLIC_CTRL_Type;
- /**
- * \brief Access to the structure of ECLIC Memory Map, which is compatible with TEE.
- */
- typedef struct {
- __IOM uint8_t CFG; /*!< Offset: 0x000 (R/W) CLIC configuration register */
- __IM uint8_t RESERVED0[3];
- __IM uint32_t INFO; /*!< Offset: 0x004 (R/ ) CLIC information register */
- __IM uint8_t RESERVED1;
- #if defined(__TEE_PRESENT) && (__TEE_PRESENT == 1)
- __IOM uint8_t STH; /*!< Offset: 0x009 (R/W ) CLIC supervisor mode interrupt-level threshold */
- #else
- __IM uint8_t RESERVED2;
- #endif
- __IM uint8_t RESERVED3;
- __IOM uint8_t MTH; /*!< Offset: 0x00B(R/W) CLIC machine mode interrupt-level threshold */
- uint32_t RESERVED4[1021];
- #if defined(__TEE_PRESENT) && (__TEE_PRESENT == 1)
- CLIC_CTRL_Type CTRL[1024]; /*!< Offset: 0x1000 (R/W) CLIC machine mode register structure for INTIP, INTIE, INTATTR, INTCTL */
- __IM uint32_t RESERVED5[2];
- __IM uint8_t RESERVED6;
- __IOM uint8_t SSTH; /*!< Offset: 0x2009 (R) CLIC supervisor mode threshold register, which is a mirror to mintthresh.sth */
- __IM uint8_t RESERVED7;
- __IM uint8_t RESERVED8;
- __IM uint32_t RESERVED9[1021];
- CLIC_CTRL_Type SCTRL[1024]; /*!< Offset: 0x3000 (R/W) CLIC supervisor mode register structure for INTIP, INTIE, INTATTR, INTCTL */
- #else
- CLIC_CTRL_Type CTRL[4096]; /*!< Offset: 0x1000 (R/W) CLIC machine mode register structure for INTIP, INTIE, INTATTR, INTCTL */
- #endif
- } CLIC_Type;
- #define CLIC_CLICCFG_NLBIT_Pos 1U /*!< CLIC CLICCFG: NLBIT Position */
- #define CLIC_CLICCFG_NLBIT_Msk (0xFUL << CLIC_CLICCFG_NLBIT_Pos) /*!< CLIC CLICCFG: NLBIT Mask */
- #define CLIC_CLICINFO_CTLBIT_Pos 21U /*!< CLIC INTINFO: CLICINTCTLBITS Position */
- #define CLIC_CLICINFO_CTLBIT_Msk (0xFUL << CLIC_CLICINFO_CTLBIT_Pos) /*!< CLIC INTINFO: CLICINTCTLBITS Mask */
- #define CLIC_CLICINFO_VER_Pos 13U /*!< CLIC CLICINFO: VERSION Position */
- #define CLIC_CLICINFO_VER_Msk (0xFFUL << CLIC_CLICINFO_VER_Pos) /*!< CLIC CLICINFO: VERSION Mask */
- #define CLIC_CLICINFO_NUM_Pos 0U /*!< CLIC CLICINFO: NUM_INTERRUPT Position */
- #define CLIC_CLICINFO_NUM_Msk (0x1FFFUL << CLIC_CLICINFO_NUM_Pos) /*!< CLIC CLICINFO: NUM_INTERRUPT Mask */
- #define CLIC_CLICINFO_SHD_NUM_Pos 25U /*!< CLIC CLICINFO: SHD_NUM Position */
- #define CLIC_CLICINFO_SHD_NUM_Msk (0xFUL << CLIC_CLICINFO_SHD_NUM_Pos) /*!< CLIC CLICINFO: SHD_NUM Mask */
- #define CLIC_INTIP_IP_Pos 0U /*!< CLIC INTIP: IP Position */
- #define CLIC_INTIP_IP_Msk (0x1UL << CLIC_INTIP_IP_Pos) /*!< CLIC INTIP: IP Mask */
- #define CLIC_INTIE_IE_Pos 0U /*!< CLIC INTIE: IE Position */
- #define CLIC_INTIE_IE_Msk (0x1UL << CLIC_INTIE_IE_Pos) /*!< CLIC INTIE: IE Mask */
- #if defined(__TEE_PRESENT) && (__TEE_PRESENT == 1)
- #define CLIC_INTATTR_MODE_Pos 6U /*!< CLIC INTATTA: Mode Position */
- #define CLIC_INTATTR_MODE_Msk (0x3U << CLIC_INTATTR_MODE_Pos) /*!< CLIC INTATTA: Mode Mask */
- #endif
- #define CLIC_INTATTR_TRIG_Pos 1U /*!< CLIC INTATTR: TRIG Position */
- #define CLIC_INTATTR_TRIG_Msk (0x3UL << CLIC_INTATTR_TRIG_Pos) /*!< CLIC INTATTR: TRIG Mask */
- #define CLIC_INTATTR_SHV_Pos 0U /*!< CLIC INTATTR: SHV Position */
- #define CLIC_INTATTR_SHV_Msk (0x1UL << CLIC_INTATTR_SHV_Pos) /*!< CLIC INTATTR: SHV Mask */
- #define ECLIC_MAX_NLBITS 8U /*!< Max nlbit of the CLICINTCTLBITS */
- #define ECLIC_MODE_MTVEC_Msk 3U /*!< ECLIC Mode mask for MTVT CSR Register */
- #define ECLIC_NON_VECTOR_INTERRUPT 0x0 /*!< Non-Vector Interrupt Mode of ECLIC */
- #define ECLIC_VECTOR_INTERRUPT 0x1 /*!< Vector Interrupt Mode of ECLIC */
- /**\brief ECLIC Trigger Enum for different Trigger Type */
- typedef enum ECLIC_TRIGGER {
- ECLIC_LEVEL_TRIGGER = 0x0, /*!< Level Triggerred, trig[0] = 0 */
- ECLIC_POSTIVE_EDGE_TRIGGER = 0x1, /*!< Postive/Rising Edge Triggered, trig[0] = 1, trig[1] = 0 */
- ECLIC_NEGTIVE_EDGE_TRIGGER = 0x3, /*!< Negtive/Falling Edge Triggered, trig[0] = 1, trig[1] = 1 */
- ECLIC_MAX_TRIGGER = 0x3 /*!< MAX Supported Trigger Mode */
- } ECLIC_TRIGGER_Type;
- #ifndef __ECLIC_BASEADDR
- /* Base address of ECLIC(__ECLIC_BASEADDR) should be defined in <Device.h> */
- #error "__ECLIC_BASEADDR is not defined, please check!"
- #endif
- #ifndef __ECLIC_INTCTLBITS
- /* Define __ECLIC_INTCTLBITS to get via ECLIC->INFO if not defined */
- #define __ECLIC_INTCTLBITS (__ECLIC_GetInfoCtlbits())
- #endif
- /* ECLIC Memory mapping of Device */
- #define ECLIC_BASE __ECLIC_BASEADDR /*!< ECLIC Base Address */
- #define ECLIC ((CLIC_Type *) ECLIC_BASE) /*!< CLIC configuration struct */
- /** @} */ /* end of group NMSIS_Core_ECLIC_Registers */
- /* ########################## ECLIC functions #################################### */
- /**
- * \defgroup NMSIS_Core_IntExc Interrupts and Exceptions
- * \brief Functions that manage interrupts and exceptions via the ECLIC.
- *
- * @{
- */
- /**
- * \brief Definition of IRQn numbers
- * \details
- * The core interrupt enumeration names for IRQn values are defined in the file <b><Device>.h</b>.
- * - Interrupt ID(IRQn) from 0 to 18 are reserved for core internal interrupts.
- * - Interrupt ID(IRQn) start from 19 represent device-specific external interrupts.
- * - The first device-specific interrupt has the IRQn value 19.
- *
- * The table below describes the core interrupt names and their availability in various Nuclei Cores.
- */
- /* The following enum IRQn 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__)
- typedef enum IRQn {
- /* ========= Nuclei N/NX Core Specific Interrupt Numbers =========== */
- /* Core Internal Interrupt IRQn definitions */
- Reserved0_IRQn = 0, /*!< Internal reserved */
- Reserved1_IRQn = 1, /*!< Internal reserved */
- Reserved2_IRQn = 2, /*!< Internal reserved */
- SysTimerSW_IRQn = 3, /*!< System Timer SW interrupt */
- Reserved3_IRQn = 4, /*!< Internal reserved */
- Reserved4_IRQn = 5, /*!< Internal reserved */
- Reserved5_IRQn = 6, /*!< Internal reserved */
- SysTimer_IRQn = 7, /*!< System Timer Interrupt */
- Reserved6_IRQn = 8, /*!< Internal reserved */
- Reserved7_IRQn = 9, /*!< Internal reserved */
- Reserved8_IRQn = 10, /*!< Internal reserved */
- Reserved9_IRQn = 11, /*!< Internal reserved */
- Reserved10_IRQn = 12, /*!< Internal reserved */
- Reserved11_IRQn = 13, /*!< Internal reserved */
- Reserved12_IRQn = 14, /*!< Internal reserved */
- Reserved13_IRQn = 15, /*!< Internal reserved */
- Reserved14_IRQn = 16, /*!< Internal reserved */
- Reserved15_IRQn = 17, /*!< Internal reserved */
- Reserved16_IRQn = 18, /*!< Internal reserved */
- /* ========= Device Specific Interrupt Numbers =================== */
- /* ToDo: add here your device specific external interrupt numbers.
- * 19~max(NUM_INTERRUPT, 1023) is reserved number for user.
- * Maxmum interrupt supported could get from clicinfo.NUM_INTERRUPT.
- * According the interrupt handlers defined in startup_Device.S
- * eg.: Interrupt for Timer#1 eclic_tim1_handler -> TIM1_IRQn */
- FirstDeviceSpecificInterrupt_IRQn = 19, /*!< First Device Specific Interrupt */
- SOC_INT_MAX, /*!< Number of total interrupts */
- } IRQn_Type;
- #endif /* __ONLY_FOR_DOXYGEN_DOCUMENT_GENERATION__ */
- #ifdef NMSIS_ECLIC_VIRTUAL
- #ifndef NMSIS_ECLIC_VIRTUAL_HEADER_FILE
- #define NMSIS_ECLIC_VIRTUAL_HEADER_FILE "nmsis_eclic_virtual.h"
- #endif
- #include NMSIS_ECLIC_VIRTUAL_HEADER_FILE
- #else
- #define ECLIC_SetCfgNlbits __ECLIC_SetCfgNlbits
- #define ECLIC_GetCfgNlbits __ECLIC_GetCfgNlbits
- #define ECLIC_GetInfoVer __ECLIC_GetInfoVer
- #define ECLIC_GetInfoCtlbits __ECLIC_GetInfoCtlbits
- #define ECLIC_GetInfoNum __ECLIC_GetInfoNum
- #define ECLIC_GetInfoShadowNum __ECLIC_GetInfoShadowNum
- #define ECLIC_SetMth __ECLIC_SetMth
- #define ECLIC_GetMth __ECLIC_GetMth
- #define ECLIC_EnableIRQ __ECLIC_EnableIRQ
- #define ECLIC_GetEnableIRQ __ECLIC_GetEnableIRQ
- #define ECLIC_DisableIRQ __ECLIC_DisableIRQ
- #define ECLIC_SetPendingIRQ __ECLIC_SetPendingIRQ
- #define ECLIC_GetPendingIRQ __ECLIC_GetPendingIRQ
- #define ECLIC_ClearPendingIRQ __ECLIC_ClearPendingIRQ
- #define ECLIC_SetTrigIRQ __ECLIC_SetTrigIRQ
- #define ECLIC_GetTrigIRQ __ECLIC_GetTrigIRQ
- #define ECLIC_SetShvIRQ __ECLIC_SetShvIRQ
- #define ECLIC_GetShvIRQ __ECLIC_GetShvIRQ
- #define ECLIC_SetCtrlIRQ __ECLIC_SetCtrlIRQ
- #define ECLIC_GetCtrlIRQ __ECLIC_GetCtrlIRQ
- #define ECLIC_SetLevelIRQ __ECLIC_SetLevelIRQ
- #define ECLIC_GetLevelIRQ __ECLIC_GetLevelIRQ
- #define ECLIC_SetPriorityIRQ __ECLIC_SetPriorityIRQ
- #define ECLIC_GetPriorityIRQ __ECLIC_GetPriorityIRQ
- #if __ECLIC_VER == 2
- #define ECLIC_EnableShadow __ECLIC_EnableShadow
- #define ECLIC_DisableShadow __ECLIC_DisableShadow
- #define ECLIC_SetShadowLevel __ECLIC_SetShadowLevel
- #define ECLIC_GetShadowLevel __ECLIC_GetShadowLevel
- #define ECLIC_SetShadowLevelReg __ECLIC_SetShadowLevelReg
- #define ECLIC_GetShadowLevelReg __ECLIC_GetShadowLevelReg
- #endif
- /* For TEE */
- #if defined(__TEE_PRESENT) && (__TEE_PRESENT == 1)
- #define ECLIC_SetModeIRQ __ECLIC_SetModeIRQ
- #define ECLIC_SetSth __ECLIC_SetSth
- #define ECLIC_GetSth __ECLIC_GetSth
- #define ECLIC_SetPendingIRQ_S __ECLIC_SetPendingIRQ_S
- #define ECLIC_GetPendingIRQ_S __ECLIC_GetPendingIRQ_S
- #define ECLIC_ClearPendingIRQ_S __ECLIC_ClearPendingIRQ_S
- #define ECLIC_SetTrigIRQ_S __ECLIC_SetTrigIRQ_S
- #define ECLIC_GetTrigIRQ_S __ECLIC_GetTrigIRQ_S
- #define ECLIC_SetShvIRQ_S __ECLIC_SetShvIRQ_S
- #define ECLIC_GetShvIRQ_S __ECLIC_GetShvIRQ_S
- #define ECLIC_SetCtrlIRQ_S __ECLIC_SetCtrlIRQ_S
- #define ECLIC_GetCtrlIRQ_S __ECLIC_GetCtrlIRQ_S
- #define ECLIC_SetLevelIRQ_S __ECLIC_SetLevelIRQ_S
- #define ECLIC_GetLevelIRQ_S __ECLIC_GetLevelIRQ_S
- #define ECLIC_SetPriorityIRQ_S __ECLIC_SetPriorityIRQ_S
- #define ECLIC_GetPriorityIRQ_S __ECLIC_GetPriorityIRQ_S
- #define ECLIC_EnableIRQ_S __ECLIC_EnableIRQ_S
- #define ECLIC_GetEnableIRQ_S __ECLIC_GetEnableIRQ_S
- #define ECLIC_DisableIRQ_S __ECLIC_DisableIRQ_S
- #if __ECLIC_VER == 2
- #define ECLIC_EnableShadow_S __ECLIC_EnableShadow_S
- #define ECLIC_DisableShadow_S __ECLIC_DisableShadow_S
- #define ECLIC_SetShadowLevel_S __ECLIC_SetShadowLevel_S
- #define ECLIC_GetShadowLevel_S __ECLIC_GetShadowLevel_S
- #define ECLIC_SetShadowLevelReg_S __ECLIC_SetShadowLevelReg_S
- #define ECLIC_GetShadowLevelReg_S __ECLIC_GetShadowLevelReg_S
- #endif
- #endif
- #endif /* NMSIS_ECLIC_VIRTUAL */
- #ifdef NMSIS_VECTAB_VIRTUAL
- #ifndef NMSIS_VECTAB_VIRTUAL_HEADER_FILE
- #define NMSIS_VECTAB_VIRTUAL_HEADER_FILE "nmsis_vectab_virtual.h"
- #endif
- #include NMSIS_VECTAB_VIRTUAL_HEADER_FILE
- #else
- #define ECLIC_SetVector __ECLIC_SetVector
- #define ECLIC_GetVector __ECLIC_GetVector
- #if defined(__TEE_PRESENT) && (__TEE_PRESENT == 1)
- #define ECLIC_SetVector_S __ECLIC_SetVector_S
- #define ECLIC_GetVector_S __ECLIC_GetVector_S
- #endif
- #endif /* (NMSIS_VECTAB_VIRTUAL) */
- /**
- * \brief Set nlbits value
- * \details
- * This function set the nlbits value of CLICCFG register.
- * \param [in] nlbits nlbits value
- * \remarks
- * - nlbits is used to set the width of level in the CLICINTCTL[i].
- * \sa
- * - \ref ECLIC_GetCfgNlbits
- */
- __STATIC_FORCEINLINE void __ECLIC_SetCfgNlbits(uint32_t nlbits)
- {
- uint8_t temp = ECLIC->CFG;
- ECLIC->CFG = (temp & ~CLIC_CLICCFG_NLBIT_Msk) | \
- ((uint8_t)((nlbits << CLIC_CLICCFG_NLBIT_Pos) & CLIC_CLICCFG_NLBIT_Msk));
- }
- /**
- * \brief Get nlbits value
- * \details
- * This function get the nlbits value of CLICCFG register.
- * \return nlbits value of CLICCFG register
- * \remarks
- * - nlbits is used to set the width of level in the CLICINTCTL[i].
- * \sa
- * - \ref ECLIC_SetCfgNlbits
- */
- __STATIC_FORCEINLINE uint32_t __ECLIC_GetCfgNlbits(void)
- {
- return ((uint32_t)((ECLIC->CFG & CLIC_CLICCFG_NLBIT_Msk) >> CLIC_CLICCFG_NLBIT_Pos));
- }
- /**
- * \brief Get the ECLIC version number
- * \details
- * This function gets the hardware version information from CLICINFO register.
- * \return hardware version number in CLICINFO register.
- * \remarks
- * - This function gets harware version information from CLICINFO register.
- * - Bit 20:17 for architecture version, bit 16:13 for implementation version.
- * \sa
- * - \ref ECLIC_GetInfoNum
- */
- __STATIC_FORCEINLINE uint32_t __ECLIC_GetInfoVer(void)
- {
- return ((uint32_t)((ECLIC->INFO & CLIC_CLICINFO_VER_Msk) >> CLIC_CLICINFO_VER_Pos));
- }
- /**
- * \brief Get CLICINTCTLBITS
- * \details
- * This function gets CLICINTCTLBITS from CLICINFO register.
- * \return CLICINTCTLBITS from CLICINFO register.
- * \remarks
- * - In the CLICINTCTL[i] registers, with 2 <= CLICINTCTLBITS <= 8.
- * - The implemented bits are kept left-justified in the most-significant bits of each 8-bit
- * CLICINTCTL[I] register, with the lower unimplemented bits hardwired to 1.
- * \sa
- * - \ref ECLIC_GetInfoNum
- */
- __STATIC_FORCEINLINE uint32_t __ECLIC_GetInfoCtlbits(void)
- {
- return ((uint32_t)((ECLIC->INFO & CLIC_CLICINFO_CTLBIT_Msk) >> CLIC_CLICINFO_CTLBIT_Pos));
- }
- /**
- * \brief Get number of maximum interrupt inputs supported
- * \details
- * This function gets number of maximum interrupt inputs supported from CLICINFO register.
- * \return number of maximum interrupt inputs supported from CLICINFO register.
- * \remarks
- * - This function gets number of maximum interrupt inputs supported from CLICINFO register.
- * - The num_interrupt field specifies the actual number of maximum interrupt inputs supported in this implementation.
- * \sa
- * - \ref ECLIC_GetInfoCtlbits
- */
- __STATIC_FORCEINLINE uint32_t __ECLIC_GetInfoNum(void)
- {
- return ((uint32_t)((ECLIC->INFO & CLIC_CLICINFO_NUM_Msk) >> CLIC_CLICINFO_NUM_Pos));
- }
- /**
- * \brief Get number of shadow register groups
- * \details
- * This function gets the number of shadow register groups from the CLICINFO register.
- * This includes both the first-come-first-served dedicated interrupt shadow registers
- * and the shadow registers designed for different interrupt levels.
- * This number represents the total count for M mode; if S Mode is present, the number is the same as M Mode.
- * Note that shadow register 0 is fixed for first-come-first-served m/s-mode interrupt and cannot be configured.
- * \return number of shadow register groups from the CLICINFO register.
- * \remarks
- * - This function is only valid for ECLICv2
- * - This function gets the number of shadow register groups from the CLICINFO register.
- * \sa
- * - \ref ECLIC_GetInfoNum
- */
- __STATIC_FORCEINLINE uint32_t __ECLIC_GetInfoShadowNum(void)
- {
- return ((uint32_t)((ECLIC->INFO & (CLIC_CLICINFO_SHD_NUM_Msk)) >> CLIC_CLICINFO_SHD_NUM_Pos));
- }
- /**
- * \brief Set Machine Mode Interrupt Level Threshold
- * \details
- * This function sets machine mode interrupt level threshold.
- * This threshold is not effective immediately, if you want to safely
- * change it, you need to disable all interrupts first, and then change it,
- * and do fence and then enable all interrupts.
- * \param [in] mth Interrupt Level Threshold.
- * \sa
- * - \ref ECLIC_GetMth
- */
- __STATIC_FORCEINLINE void __ECLIC_SetMth(uint8_t mth)
- {
- ECLIC->MTH = mth;
- }
- /**
- * \brief Get Machine Mode Interrupt Level Threshold
- * \details
- * This function gets machine mode interrupt level threshold.
- * \return Interrupt Level Threshold.
- * \sa
- * - \ref ECLIC_SetMth
- */
- __STATIC_FORCEINLINE uint8_t __ECLIC_GetMth(void)
- {
- return (ECLIC->MTH);
- }
- /**
- * \brief Enable a specific interrupt
- * \details
- * This function enables the specific interrupt \em IRQn.
- * \param [in] IRQn Interrupt number
- * \remarks
- * - IRQn must not be negative.
- * \sa
- * - \ref ECLIC_DisableIRQ
- */
- __STATIC_FORCEINLINE void __ECLIC_EnableIRQ(IRQn_Type IRQn)
- {
- ECLIC->CTRL[IRQn].INTIE |= CLIC_INTIE_IE_Msk;
- }
- /**
- * \brief Get a specific interrupt enable status
- * \details
- * This function returns the interrupt enable status for the specific interrupt \em IRQn.
- * \param [in] IRQn Interrupt number
- * \returns
- * - 0 Interrupt is not enabled
- * - 1 Interrupt is pending
- * \remarks
- * - IRQn must not be negative.
- * \sa
- * - \ref ECLIC_EnableIRQ
- * - \ref ECLIC_DisableIRQ
- */
- __STATIC_FORCEINLINE uint32_t __ECLIC_GetEnableIRQ(IRQn_Type IRQn)
- {
- return ((uint32_t) (ECLIC->CTRL[IRQn].INTIE) & CLIC_INTIE_IE_Msk);
- }
- /**
- * \brief Disable a specific interrupt
- * \details
- * This function disables the specific interrupt \em IRQn.
- * \param [in] IRQn Number of the external interrupt to disable
- * \remarks
- * - IRQn must not be negative.
- * \sa
- * - \ref ECLIC_EnableIRQ
- */
- __STATIC_FORCEINLINE void __ECLIC_DisableIRQ(IRQn_Type IRQn)
- {
- ECLIC->CTRL[IRQn].INTIE &= ~CLIC_INTIE_IE_Msk;
- }
- /**
- * \brief Get the pending specific interrupt
- * \details
- * This function returns the pending status of the specific interrupt \em IRQn.
- * \param [in] IRQn Interrupt number
- * \returns
- * - 0 Interrupt is not pending
- * - 1 Interrupt is pending
- * \remarks
- * - IRQn must not be negative.
- * \sa
- * - \ref ECLIC_SetPendingIRQ
- * - \ref ECLIC_ClearPendingIRQ
- */
- __STATIC_FORCEINLINE int32_t __ECLIC_GetPendingIRQ(IRQn_Type IRQn)
- {
- return ((uint32_t)(ECLIC->CTRL[IRQn].INTIP) & CLIC_INTIP_IP_Msk);
- }
- /**
- * \brief Set a specific interrupt to pending
- * \details
- * This function sets the pending bit for the specific interrupt \em IRQn.
- * \param [in] IRQn Interrupt number
- * \remarks
- * - IRQn must not be negative.
- * \sa
- * - \ref ECLIC_GetPendingIRQ
- * - \ref ECLIC_ClearPendingIRQ
- */
- __STATIC_FORCEINLINE void __ECLIC_SetPendingIRQ(IRQn_Type IRQn)
- {
- ECLIC->CTRL[IRQn].INTIP |= CLIC_INTIP_IP_Msk;
- }
- /**
- * \brief Clear a specific interrupt from pending
- * \details
- * This function removes the pending state of the specific interrupt \em IRQn.
- * \em IRQn cannot be a negative number.
- * \param [in] IRQn Interrupt number
- * \remarks
- * - IRQn must not be negative.
- * \sa
- * - \ref ECLIC_SetPendingIRQ
- * - \ref ECLIC_GetPendingIRQ
- */
- __STATIC_FORCEINLINE void __ECLIC_ClearPendingIRQ(IRQn_Type IRQn)
- {
- ECLIC->CTRL[IRQn].INTIP &= ~CLIC_INTIP_IP_Msk;
- }
- /**
- * \brief Set trigger mode and polarity for a specific interrupt
- * \details
- * This function set trigger mode and polarity of the specific interrupt \em IRQn.
- * \param [in] IRQn Interrupt number
- * \param [in] trig
- * - 00 level trigger, \ref ECLIC_LEVEL_TRIGGER
- * - 01 positive edge trigger, \ref ECLIC_POSTIVE_EDGE_TRIGGER
- * - 02 level trigger, \ref ECLIC_LEVEL_TRIGGER
- * - 03 negative edge trigger, \ref ECLIC_NEGTIVE_EDGE_TRIGGER
- * \remarks
- * - IRQn must not be negative.
- *
- * \sa
- * - \ref ECLIC_GetTrigIRQ
- */
- __STATIC_FORCEINLINE void __ECLIC_SetTrigIRQ(IRQn_Type IRQn, uint32_t trig)
- {
- uint8_t temp = ECLIC->CTRL[IRQn].INTATTR;
- ECLIC->CTRL[IRQn].INTATTR = (temp & ~CLIC_INTATTR_TRIG_Msk) | \
- ((uint8_t)(trig << CLIC_INTATTR_TRIG_Pos));
- }
- /**
- * \brief Get trigger mode and polarity for a specific interrupt
- * \details
- * This function get trigger mode and polarity of the specific interrupt \em IRQn.
- * \param [in] IRQn Interrupt number
- * \return
- * - 00 level trigger, \ref ECLIC_LEVEL_TRIGGER
- * - 01 positive edge trigger, \ref ECLIC_POSTIVE_EDGE_TRIGGER
- * - 02 level trigger, \ref ECLIC_LEVEL_TRIGGER
- * - 03 negative edge trigger, \ref ECLIC_NEGTIVE_EDGE_TRIGGER
- * \remarks
- * - IRQn must not be negative.
- * \sa
- * - \ref ECLIC_SetTrigIRQ
- */
- __STATIC_FORCEINLINE uint32_t __ECLIC_GetTrigIRQ(IRQn_Type IRQn)
- {
- return ((uint32_t)(((ECLIC->CTRL[IRQn].INTATTR) & CLIC_INTATTR_TRIG_Msk) >> CLIC_INTATTR_TRIG_Pos));
- }
- /**
- * \brief Set interrupt working mode for a specific interrupt
- * \details
- * This function set selective hardware vector or non-vector working mode of the specific interrupt \em IRQn.
- * \param [in] IRQn Interrupt number
- * \param [in] shv
- * - 0 non-vector mode, \ref ECLIC_NON_VECTOR_INTERRUPT
- * - 1 vector mode, \ref ECLIC_VECTOR_INTERRUPT
- * \remarks
- * - IRQn must not be negative.
- * \sa
- * - \ref ECLIC_GetShvIRQ
- */
- __STATIC_FORCEINLINE void __ECLIC_SetShvIRQ(IRQn_Type IRQn, uint32_t shv)
- {
- uint8_t temp = ECLIC->CTRL[IRQn].INTATTR;
- ECLIC->CTRL[IRQn].INTATTR = (temp & ~CLIC_INTATTR_SHV_Msk) | \
- ((uint8_t)(shv << CLIC_INTATTR_SHV_Pos));
- }
- /**
- * \brief Get interrupt working mode for a specific interrupt
- * \details
- * This function get selective hardware vector or non-vector working mode of the specific interrupt \em IRQn.
- * \param [in] IRQn Interrupt number
- * \return shv
- * - 0 non-vector mode, \ref ECLIC_NON_VECTOR_INTERRUPT
- * - 1 vector mode, \ref ECLIC_VECTOR_INTERRUPT
- * \remarks
- * - IRQn must not be negative.
- * \sa
- * - \ref ECLIC_SetShvIRQ
- */
- __STATIC_FORCEINLINE uint32_t __ECLIC_GetShvIRQ(IRQn_Type IRQn)
- {
- return ((uint32_t)(((ECLIC->CTRL[IRQn].INTATTR) & CLIC_INTATTR_SHV_Msk) >> CLIC_INTATTR_SHV_Pos));
- }
- /**
- * \brief Modify ECLIC Interrupt Input Control Register for a specific interrupt
- * \details
- * This function modify ECLIC Interrupt Input Control(CLICINTCTL[i]) register of the specific interrupt \em IRQn.
- * \param [in] IRQn Interrupt number
- * \param [in] intctrl Set value for CLICINTCTL[i] register
- * \remarks
- * - IRQn must not be negative.
- * \sa
- * - \ref ECLIC_GetCtrlIRQ
- */
- __STATIC_FORCEINLINE void __ECLIC_SetCtrlIRQ(IRQn_Type IRQn, uint8_t intctrl)
- {
- ECLIC->CTRL[IRQn].INTCTRL = intctrl;
- }
- /**
- * \brief Get ECLIC Interrupt Input Control Register value for a specific interrupt
- * \details
- * This function modify ECLIC Interrupt Input Control register of the specific interrupt \em IRQn.
- * \param [in] IRQn Interrupt number
- * \return value of ECLIC Interrupt Input Control register
- * \remarks
- * - IRQn must not be negative.
- * \sa
- * - \ref ECLIC_SetCtrlIRQ
- */
- __STATIC_FORCEINLINE uint8_t __ECLIC_GetCtrlIRQ(IRQn_Type IRQn)
- {
- return (ECLIC->CTRL[IRQn].INTCTRL);
- }
- /**
- * \brief Set ECLIC Interrupt level of a specific interrupt
- * \details
- * This function set interrupt level of the specific interrupt \em IRQn.
- * \param [in] IRQn Interrupt number
- * \param [in] lvl_abs Interrupt level
- * \remarks
- * - IRQn must not be negative.
- * - If lvl_abs to be set is larger than the max level allowed, it will be force to be max level.
- * - When you set level value you need use clciinfo.nlbits to get the width of level.
- * Then we could know the maximum of level. CLICINTCTLBITS is how many total bits are
- * present in the CLICINTCTL register.
- * \sa
- * - \ref ECLIC_GetLevelIRQ
- */
- __STATIC_INLINE void __ECLIC_SetLevelIRQ(IRQn_Type IRQn, uint8_t lvl_abs)
- {
- uint8_t nlbits = __ECLIC_GetCfgNlbits();
- uint8_t intctlbits = (uint8_t)__ECLIC_INTCTLBITS;
- if (nlbits == 0) {
- return;
- }
- if (nlbits > intctlbits) {
- nlbits = intctlbits;
- }
- uint8_t maxlvl = ((1UL << nlbits) - 1);
- if (lvl_abs > maxlvl) {
- lvl_abs = maxlvl;
- }
- uint8_t lvl = lvl_abs << (ECLIC_MAX_NLBITS - nlbits);
- uint8_t cur_ctrl = __ECLIC_GetCtrlIRQ(IRQn);
- cur_ctrl = cur_ctrl << nlbits;
- cur_ctrl = cur_ctrl >> nlbits;
- __ECLIC_SetCtrlIRQ(IRQn, (cur_ctrl | lvl));
- }
- /**
- * \brief Get ECLIC Interrupt level of a specific interrupt
- * \details
- * This function get interrupt level of the specific interrupt \em IRQn.
- * \param [in] IRQn Interrupt number
- * \return Interrupt level
- * \remarks
- * - IRQn must not be negative.
- * \sa
- * - \ref ECLIC_SetLevelIRQ
- */
- __STATIC_INLINE uint8_t __ECLIC_GetLevelIRQ(IRQn_Type IRQn)
- {
- uint8_t nlbits = __ECLIC_GetCfgNlbits();
- uint8_t intctlbits = (uint8_t)__ECLIC_INTCTLBITS;
- if (nlbits == 0) {
- return 0;
- }
- if (nlbits > intctlbits) {
- nlbits = intctlbits;
- }
- uint8_t intctrl = __ECLIC_GetCtrlIRQ(IRQn);
- uint8_t lvl_abs = intctrl >> (ECLIC_MAX_NLBITS - nlbits);
- return lvl_abs;
- }
- /**
- * \brief Get ECLIC Interrupt priority of a specific interrupt
- * \details
- * This function get interrupt priority of the specific interrupt \em IRQn.
- * \param [in] IRQn Interrupt number
- * \param [in] pri Interrupt priority
- * \remarks
- * - IRQn must not be negative.
- * - If pri to be set is larger than the max priority allowed, it will be force to be max priority.
- * - Priority width is CLICINTCTLBITS minus clciinfo.nlbits if clciinfo.nlbits
- * is less than CLICINTCTLBITS. Otherwise priority width is 0.
- * \sa
- * - \ref ECLIC_GetPriorityIRQ
- */
- __STATIC_INLINE void __ECLIC_SetPriorityIRQ(IRQn_Type IRQn, uint8_t pri)
- {
- uint8_t nlbits = __ECLIC_GetCfgNlbits();
- uint8_t intctlbits = (uint8_t)__ECLIC_INTCTLBITS;
- if (nlbits < intctlbits) {
- uint8_t maxpri = ((1UL << (intctlbits - nlbits)) - 1);
- if (pri > maxpri) {
- pri = maxpri;
- }
- pri = pri << (ECLIC_MAX_NLBITS - intctlbits);
- uint8_t mask = ((uint8_t)(-1)) >> intctlbits;
- pri = pri | mask;
- uint8_t cur_ctrl = __ECLIC_GetCtrlIRQ(IRQn);
- cur_ctrl = cur_ctrl >> (ECLIC_MAX_NLBITS - nlbits);
- cur_ctrl = cur_ctrl << (ECLIC_MAX_NLBITS - nlbits);
- __ECLIC_SetCtrlIRQ(IRQn, (cur_ctrl | pri));
- }
- }
- /**
- * \brief Get ECLIC Interrupt priority of a specific interrupt
- * \details
- * This function get interrupt priority of the specific interrupt \em IRQn.
- * \param [in] IRQn Interrupt number
- * \return Interrupt priority
- * \remarks
- * - IRQn must not be negative.
- * \sa
- * - \ref ECLIC_SetPriorityIRQ
- */
- __STATIC_INLINE uint8_t __ECLIC_GetPriorityIRQ(IRQn_Type IRQn)
- {
- uint8_t nlbits = __ECLIC_GetCfgNlbits();
- uint8_t intctlbits = (uint8_t)__ECLIC_INTCTLBITS;
- if (nlbits < intctlbits) {
- uint8_t cur_ctrl = __ECLIC_GetCtrlIRQ(IRQn);
- uint8_t pri = cur_ctrl << nlbits;
- pri = pri >> nlbits;
- pri = pri >> (ECLIC_MAX_NLBITS - intctlbits);
- return pri;
- } else {
- return 0;
- }
- }
- #if __ECLIC_VER == 2
- /**
- * \brief Enable ECLIC Shadow Register Function (Machine Mode)
- * \details
- * This function enables the shadow register function for ECLIC in Machine Mode.
- * It sets the MECLIC_CTL_SHADOW_EN bit in the CSR_MECLIC_CTL CSR.
- * This function is only valid for ECLIC version 2 and above.
- * \remarks
- * - API only available for ECLIC v2
- * \sa
- * - \ref __ECLIC_DisableShadow
- */
- __STATIC_FORCEINLINE void __ECLIC_EnableShadow(void)
- {
- __RV_CSR_SET(CSR_MECLIC_CTL, MECLIC_CTL_SHADOW_EN);
- }
- /**
- * \brief Disable ECLIC Shadow Register Function (Machine Mode)
- * \details
- * This function disables the shadow register function for ECLIC in Machine Mode.
- * It clears the MECLIC_CTL_SHADOW_EN bit in the CSR_MECLIC_CTL CSR.
- * This function is only valid for ECLIC version 2 and above.
- * \remarks
- * - API only available for ECLIC v2
- * \sa
- * - \ref __ECLIC_EnableShadow
- */
- __STATIC_FORCEINLINE void __ECLIC_DisableShadow(void)
- {
- __RV_CSR_CLEAR(CSR_MECLIC_CTL, MECLIC_CTL_SHADOW_EN);
- }
- /**
- * \brief Set Shadow Register Interrupt Level for a specific m-mode shadow register
- * \details
- * This function sets the interrupt level for a specific m-mode shadow register \em idx + 1.
- * It configures CSR_MSHADGPRLVL0 and CSR_MSHADGPRLVL1 registers.
- * \param [in] idx Shadow register index (0-7), corresponding to shadow registers 1-8
- * (Note: shadow register 0 is fixed for first-come-first-served m-mode
- * interrupt and cannot be configured)
- * \param [in] level Interrupt level to set for the shadow register
- * \remarks
- * - API only available for ECLIC v2
- * - idx = 0 means set SHAD1_CFG, which configures the shadow register 1
- * - For RV64, all 8 shadow registers are configured in CSR_MSHADGPRLVL0
- * - For RV32, shadow registers 1-4 are in lower 32 bits of CSR_MSHADGPRLVL0,
- * and shadow registers 5-8 are in CSR_MSHADGPRLVL1
- * \sa
- * - \ref ECLIC_GetShadowLevel
- */
- __STATIC_INLINE void __ECLIC_SetShadowLevel(unsigned long idx, uint8_t level)
- {
- /* Check if idx is valid (0-7) */
- if (idx > 7) {
- return;
- }
- uint8_t nlbits = (uint8_t)__ECLIC_GetCfgNlbits();
- /* Limit the level value to the available number of bits */
- uint8_t max_level = (1U << nlbits) - 1;
- if (level > max_level) {
- level = max_level;
- }
- /* Position the level value in the upper nlbits of the 8-bit field and set the low (8-nlbits) bits to 1 */
- uint8_t level_shifted = (uint8_t)((level << (8 - nlbits)) | ((1U << (8 - nlbits)) - 1));
- #if __RISCV_XLEN == 64
- /* For RV64, all 8 shadow registers are in CSR_MSHADGPRLVL0 */
- /* Calculate the bit position for the 8-bit field of the specified index */
- uint32_t bit_pos = idx << 3; /* idx * 8 using bit shift */
- /* Create mask to clear the 8-bit field for the specified index */
- uint64_t mask = (uint64_t)0xFFUL << bit_pos;
- /* Read, modify, and write the CSR register */
- uint64_t current_val = __RV_CSR_READ(CSR_MSHADGPRLVL0);
- current_val = (current_val & ~mask) | (((uint64_t)level_shifted) << bit_pos);
- __RV_CSR_WRITE(CSR_MSHADGPRLVL0, current_val);
- #else
- /* For RV32, calculate bit position and select appropriate register */
- if (idx < 4) {
- /* Shadow registers 1-4 are in CSR_MSHADGPRLVL0 */
- uint32_t bit_pos = idx << 3; /* idx * 8 using bit shift */
- uint32_t mask = 0xFFUL << bit_pos;
- uint32_t current_val = __RV_CSR_READ(CSR_MSHADGPRLVL0);
- current_val = (current_val & ~mask) | (((uint32_t)level_shifted) << bit_pos);
- __RV_CSR_WRITE(CSR_MSHADGPRLVL0, current_val);
- } else {
- /* Shadow registers 5-8 are in CSR_MSHADGPRLVL1 */
- uint32_t bit_pos = (idx - 4) << 3; /* (idx - 4) * 8 using bit shift */
- uint32_t mask = 0xFFUL << bit_pos;
- uint32_t current_val = __RV_CSR_READ(CSR_MSHADGPRLVL1);
- current_val = (current_val & ~mask) | (((uint32_t)level_shifted) << bit_pos);
- __RV_CSR_WRITE(CSR_MSHADGPRLVL1, current_val);
- }
- #endif
- }
- /**
- * \brief Get Shadow Register Interrupt Level for a specific m-mode shadow register
- * \details
- * This function gets the interrupt level for a specific m-mode shadow register \em idx + 1.
- * It reads CSR_MSHADGPRLVL0 and CSR_MSHADGPRLVL1 registers.
- * \param [in] idx Shadow register index (0-7), corresponding to shadow registers 1-8
- * (Note: shadow register 0 is fixed for first-come-first-served m-mode
- * interrupt and cannot be configured)
- * \return Interrupt level of the shadow register
- * \remarks
- * - API only available for ECLIC v2
- * - idx = 0 means set SHAD1_CFG, which configures the shadow register 1
- * - For RV64, all 8 shadow registers are configured in CSR_MSHADGPRLVL0
- * - For RV32, shadow registers 1-4 are in lower 32 bits of CSR_MSHADGPRLVL0,
- * and shadow registers 5-8 are in CSR_MSHADGPRLVL1
- * \sa
- * - \ref ECLIC_SetShadowLevel
- */
- __STATIC_INLINE uint8_t __ECLIC_GetShadowLevel(unsigned long idx)
- {
- /* Check if idx is valid (0-7) */
- if (idx > 7) {
- return 0;
- }
- uint8_t nlbits = (uint8_t)__ECLIC_GetCfgNlbits();
- #if __RISCV_XLEN == 64
- /* For RV64, all 8 shadow registers are in CSR_MSHADGPRLVL0 */
- /* Calculate the bit position for the 8-bit field of the specified index */
- uint32_t bit_pos = idx << 3; /* idx * 8 using bit shift */
- /* Read the CSR register and extract the 8-bit field */
- uint64_t current_val = __RV_CSR_READ(CSR_MSHADGPRLVL0);
- uint8_t extracted_val = (uint8_t)((current_val >> bit_pos) & 0xFF);
- /* Extract the level from the upper nlbits of the 8-bit field */
- uint8_t level = (extracted_val >> (8 - nlbits));
- return level;
- #else
- /* For RV32, calculate bit position and select appropriate register */
- if (idx < 4) {
- /* Shadow registers 1-4 are in CSR_MSHADGPRLVL0 */
- uint32_t bit_pos = idx << 3; /* idx * 8 using bit shift */
- /* Read the CSR register and extract the 8-bit field */
- uint32_t current_val = __RV_CSR_READ(CSR_MSHADGPRLVL0);
- uint8_t extracted_val = (uint8_t)((current_val >> bit_pos) & 0xFF);
- /* Extract the level from the upper nlbits of the 8-bit field */
- uint8_t level = (extracted_val >> (8 - nlbits));
- return level;
- } else {
- /* Shadow registers 5-8 are in CSR_MSHADGPRLVL1 */
- uint32_t bit_pos = (idx - 4) << 3; /* (idx - 4) * 8 using bit shift */
- /* Read the CSR register and extract the 8-bit field */
- uint32_t current_val = __RV_CSR_READ(CSR_MSHADGPRLVL1);
- uint8_t extracted_val = (uint8_t)((current_val >> bit_pos) & 0xFF);
- /* Extract the level from the upper nlbits of the 8-bit field */
- uint8_t level = (extracted_val >> (8 - nlbits));
- return level;
- }
- #endif
- }
- /**
- * \brief Set Shadow Register Level Register for m-mode
- * \details
- * This function sets the entire shadow register level register for m-mode.
- * It writes directly to CSR_MSHADGPRLVL0 register (and CSR_MSHADGPRLVL1 for RV32).
- * \param [in] value 64-bit value to set for the shadow register level register
- * \remarks
- * - API only available for ECLIC v2
- * - For RV64, all 8 shadow registers are configured in CSR_MSHADGPRLVL0
- * - For RV32, shadow registers 1-4 are in lower 32 bits of CSR_MSHADGPRLVL0,
- * and shadow registers 5-8 are in CSR_MSHADGPRLVL1
- * - Note: shadow register 0 is fixed for first-come-first-served m-mode interrupt and cannot be configured
- * \sa
- * - \ref ECLIC_GetShadowLevelReg
- */
- __STATIC_INLINE void __ECLIC_SetShadowLevelReg(uint64_t value)
- {
- #if __RISCV_XLEN == 64
- __RV_CSR_WRITE(CSR_MSHADGPRLVL0, value);
- #else
- __RV_CSR_WRITE(CSR_MSHADGPRLVL0, (uint32_t)value);
- __RV_CSR_WRITE(CSR_MSHADGPRLVL1, (uint32_t)(value >> 32));
- #endif
- }
- /**
- * \brief Get Shadow Register Level Register for m-mode
- * \details
- * This function gets the entire shadow register level register for m-mode.
- * It reads from CSR_MSHADGPRLVL0 register (and CSR_MSHADGPRLVL1 for RV32) and combines them.
- * \return 64-bit value of the shadow register level register
- * \remarks
- * - API only available for ECLIC v2
- * - For RV64, all 8 shadow registers are configured in CSR_MSHADGPRLVL0
- * - For RV32, shadow registers 1-4 are in lower 32 bits of CSR_MSHADGPRLVL0,
- * and shadow registers 5-8 are in CSR_MSHADGPRLVL1
- * - Note: shadow register 0 is fixed for first-come-first-served m-mode interrupt and cannot be configured
- * \sa
- * - \ref ECLIC_SetShadowLevelReg
- */
- __STATIC_INLINE uint64_t __ECLIC_GetShadowLevelReg(void)
- {
- #if __RISCV_XLEN == 64
- return __RV_CSR_READ(CSR_MSHADGPRLVL0);
- #else
- uint64_t value = __RV_CSR_READ(CSR_MSHADGPRLVL1);
- value <<= 32;
- value |= __RV_CSR_READ(CSR_MSHADGPRLVL0);
- return value;
- #endif
- }
- #endif
- /**
- * \brief Set Interrupt Vector of a specific interrupt
- * \details
- * This function set interrupt handler address of the specific interrupt \em IRQn.
- * \param [in] IRQn Interrupt number
- * \param [in] vector Interrupt handler address
- * \remarks
- * - IRQn must not be negative.
- * - You can set the \ref CSR_CSR_MTVT to set interrupt vector table entry address.
- * - If your vector table is placed in readonly section, the vector for IRQn will not be modified.
- * For this case, you need to use the correct irq handler name defined in your vector table as
- * your irq handler function name.
- * - This function will only work correctly when the vector table is placed in an read-write enabled section.
- * \sa
- * - \ref ECLIC_GetVector
- */
- __STATIC_INLINE void __ECLIC_SetVector(IRQn_Type IRQn, rv_csr_t vector)
- {
- unsigned long vec_base;
- vec_base = ((unsigned long)__RV_CSR_READ(CSR_MTVT));
- vec_base += ((unsigned long)IRQn) * sizeof(unsigned long);
- (* (unsigned long *) vec_base) = vector;
- #if (defined(__DCACHE_PRESENT) && (__DCACHE_PRESENT == 1))
- #if (defined(__CCM_PRESENT) && (__CCM_PRESENT == 1))
- MFlushDCacheLine((unsigned long)vec_base);
- #endif
- #endif
- #if (defined(__ICACHE_PRESENT) && (__ICACHE_PRESENT == 1))
- #if (defined(__CCM_PRESENT) && (__CCM_PRESENT == 1))
- MInvalICacheLine((unsigned long)vec_base);
- #else
- __FENCE_I();
- #endif
- #endif
- }
- /**
- * \brief Get Interrupt Vector of a specific interrupt
- * \details
- * This function get interrupt handler address of the specific interrupt \em IRQn.
- * \param [in] IRQn Interrupt number
- * \return Interrupt handler address
- * \remarks
- * - IRQn must not be negative.
- * - You can read \ref CSR_CSR_MTVT to get interrupt vector table entry address.
- * \sa
- * - \ref ECLIC_SetVector
- */
- __STATIC_FORCEINLINE rv_csr_t __ECLIC_GetVector(IRQn_Type IRQn)
- {
- #if __RISCV_XLEN == 32
- return (*(uint32_t *)(__RV_CSR_READ(CSR_MTVT) + IRQn * 4));
- #elif __RISCV_XLEN == 64
- return (*(uint64_t *)(__RV_CSR_READ(CSR_MTVT) + IRQn * 8));
- #else // TODO Need cover for XLEN=128 case in future
- return (*(uint64_t *)(__RV_CSR_READ(CSR_MTVT) + IRQn * 8));
- #endif
- }
- #if defined(__TEE_PRESENT) && (__TEE_PRESENT == 1)
- /**
- * \brief Set privilege mode of a specific interrupt
- * \details
- * This function set in which privilege mode the interrupts \em IRQn should be taken.
- * \param [in] IRQn Interrupt number
- * \param [in] mode Privilege mode
- * \remarks
- * - IRQn must not be negative.
- * - mode must be 1(Supervisor Mode) or 3(Machine Mode), other values are ignored.
- * - M-mode can R/W this field, but S-mode can only read.And ECLIC with TEE does not
- * reply on CSR mideleg to delegate interrupts.
- * - Mode of S-mode ECLIC region's clicintattr can be omitted to set, which is mirror to M-mode ECLIC region's.
- * Only the low 6 bits of clicintattr [i] can be written via the S-mode memory region.
- */
- __STATIC_FORCEINLINE void __ECLIC_SetModeIRQ(IRQn_Type IRQn, uint32_t mode)
- {
- /*
- * only 1 or 3 can be assigned to mode in one step.the default value of mode is 3,
- * which can't be clear to 0 firstly, then OR it to 1
- */
- ECLIC->CTRL[IRQn].INTATTR = (uint8_t)(mode << CLIC_INTATTR_MODE_Pos) + \
- (ECLIC->SCTRL[IRQn].INTATTR & (~CLIC_INTATTR_MODE_Msk));
- }
- /**
- * \brief Set supervisor-mode Interrupt Level Threshold in supervisor mode
- * \details
- * This function sets supervisor-mode interrupt level threshold.
- * \param [in] sth Interrupt Level Threshold.
- * \remarks
- * - S-mode ECLIC region sintthresh'sth is a mirror to M-mode ECLIC region's mintthresh.sth,
- * and will be updated synchronously, here operate on mintthresh.sth.
- * - Similiar to \ref ECLIC_SetMth, also recommended to disable interrupts before
- * setting interrupt level threshold.
- * \sa
- * - \ref ECLIC_GetSth
- */
- __STATIC_FORCEINLINE void __ECLIC_SetSth(uint8_t sth)
- {
- ECLIC->STH = sth;
- }
- /**
- * \brief Get supervisor-mode Interrupt Level Threshold in supervisor mode
- * \details
- * This function gets supervisor mode interrupt level threshold.
- * \return Interrupt Level Threshold.
- * \remarks
- * - S-mode ECLIC region sintthresh'sth is a mirror to M-mode ECLIC region's mintthresh.sth,
- * and will be updated synchronously, here operate on mintthresh.sth.
- * \sa
- * - \ref ECLIC_SetSth
- */
- __STATIC_FORCEINLINE uint8_t __ECLIC_GetSth(void)
- {
- return (ECLIC->STH);
- }
- /**
- * \brief Set a specific interrupt to pending in supervisor mode
- * \details
- * This function sets the pending bit for the specific interrupt \em IRQn in supervisor mode.
- * \param [in] IRQn Interrupt number
- * \remarks
- * - IRQn must not be negative.
- * \sa
- * - \ref ECLIC_GetPendingIRQ_S
- * - \ref ECLIC_ClearPendingIRQ_S
- */
- __STATIC_FORCEINLINE void __ECLIC_SetPendingIRQ_S(IRQn_Type IRQn)
- {
- ECLIC->SCTRL[IRQn].INTIP |= CLIC_INTIP_IP_Msk;
- }
- /**
- * \brief Get the pending specific interrupt in supervisor mode
- * \details
- * This function returns the pending status of the specific interrupt \em IRQn in supervisor mode.
- * \param [in] IRQn Interrupt number
- * \returns
- * - 0 Interrupt is not pending
- * - 1 Interrupt is pending
- * \remarks
- * - IRQn must not be negative.
- * \sa
- * - \ref ECLIC_SetPendingIRQ_S
- * - \ref ECLIC_ClearPendingIRQ_S
- */
- __STATIC_FORCEINLINE int32_t __ECLIC_GetPendingIRQ_S(IRQn_Type IRQn)
- {
- return ((uint32_t)(ECLIC->SCTRL[IRQn].INTIP) & CLIC_INTIP_IP_Msk);
- }
- /**
- * \brief Clear a specific interrupt from pending in supervisor mode
- * \details
- * This function removes the pending state of the specific interrupt \em IRQn in supervisor mode.
- * \em IRQn cannot be a negative number.
- * \param [in] IRQn Interrupt number
- * \remarks
- * - IRQn must not be negative.
- * \sa
- * - \ref ECLIC_SetPendingIRQ_S
- * - \ref ECLIC_GetPendingIRQ_S
- */
- __STATIC_FORCEINLINE void __ECLIC_ClearPendingIRQ_S(IRQn_Type IRQn)
- {
- ECLIC->SCTRL[IRQn].INTIP &= ~CLIC_INTIP_IP_Msk;
- }
- /**
- * \brief Set trigger mode and polarity for a specific interrupt in supervisor mode
- * \details
- * This function set trigger mode and polarity of the specific interrupt \em IRQn.
- * \param [in] IRQn Interrupt number
- * \param [in] trig
- * - 00 level trigger, \ref ECLIC_LEVEL_TRIGGER
- * - 01 positive edge trigger, \ref ECLIC_POSTIVE_EDGE_TRIGGER
- * - 02 level trigger, \ref ECLIC_LEVEL_TRIGGER
- * - 03 negative edge trigger, \ref ECLIC_NEGTIVE_EDGE_TRIGGER
- * \remarks
- * - IRQn must not be negative.
- *
- * \sa
- * - \ref ECLIC_GetTrigIRQ_S
- */
- __STATIC_FORCEINLINE void __ECLIC_SetTrigIRQ_S(IRQn_Type IRQn, uint32_t trig)
- {
- uint8_t temp = ECLIC->SCTRL[IRQn].INTATTR;
- ECLIC->SCTRL[IRQn].INTATTR = (temp & ~CLIC_INTATTR_TRIG_Msk) | \
- ((uint8_t)(trig << CLIC_INTATTR_TRIG_Pos));
- }
- /**
- * \brief Get trigger mode and polarity for a specific interrupt in supervisor mode
- * \details
- * This function get trigger mode and polarity of the specific interrupt \em IRQn.
- * \param [in] IRQn Interrupt number
- * \return
- * - 00 level trigger, \ref ECLIC_LEVEL_TRIGGER
- * - 01 positive edge trigger, \ref ECLIC_POSTIVE_EDGE_TRIGGER
- * - 02 level trigger, \ref ECLIC_LEVEL_TRIGGER
- * - 03 negative edge trigger, \ref ECLIC_NEGTIVE_EDGE_TRIGGER
- * \remarks
- * - IRQn must not be negative.
- * \sa
- * - \ref ECLIC_SetTrigIRQ_S
- */
- __STATIC_FORCEINLINE uint8_t __ECLIC_GetTrigIRQ_S(IRQn_Type IRQn)
- {
- return ((uint8_t)(((ECLIC->SCTRL[IRQn].INTATTR) & CLIC_INTATTR_TRIG_Msk) >> CLIC_INTATTR_TRIG_Pos));
- }
- /**
- * \brief Set interrupt working mode for a specific interrupt in supervisor mode
- * \details
- * This function set selective hardware vector or non-vector working mode of the specific interrupt \em IRQn.
- * \param [in] IRQn Interrupt number
- * \param [in] shv
- * - 0 non-vector mode, \ref ECLIC_NON_VECTOR_INTERRUPT
- * - 1 vector mode, \ref ECLIC_VECTOR_INTERRUPT
- * \remarks
- * - IRQn must not be negative.
- * \sa
- * - \ref ECLIC_GetShvIRQ_S
- */
- __STATIC_FORCEINLINE void __ECLIC_SetShvIRQ_S(IRQn_Type IRQn, uint32_t shv)
- {
- uint8_t temp = ECLIC->SCTRL[IRQn].INTATTR;
- ECLIC->SCTRL[IRQn].INTATTR = (temp & ~CLIC_INTATTR_SHV_Msk) | \
- ((uint8_t)(shv << CLIC_INTATTR_SHV_Pos));
- }
- /**
- * \brief Get interrupt working mode for a specific interrupt in supervisor mode
- * \details
- * This function get selective hardware vector or non-vector working mode of the specific interrupt \em IRQn.
- * \param [in] IRQn Interrupt number
- * \return shv
- * - 0 non-vector mode, \ref ECLIC_NON_VECTOR_INTERRUPT
- * - 1 vector mode, \ref ECLIC_VECTOR_INTERRUPT
- * \remarks
- * - IRQn must not be negative.
- * \sa
- * - \ref ECLIC_SMODE_SetShvIRQ
- */
- __STATIC_FORCEINLINE uint8_t __ECLIC_GetShvIRQ_S(IRQn_Type IRQn)
- {
- return ((uint8_t)(((ECLIC->SCTRL[IRQn].INTATTR) & CLIC_INTATTR_SHV_Msk) >> CLIC_INTATTR_SHV_Pos));
- }
- /**
- * \brief Modify ECLIC Interrupt Input Control Register for a specific interrupt in supervisor mode
- * \details
- * This function modify ECLIC Interrupt Input Control(CLICINTCTL[i]) register of the specific interrupt \em IRQn.
- * \param [in] IRQn Interrupt number
- * \param [in] intctrl Set value for CLICINTCTL[i] register
- * \remarks
- * - IRQn must not be negative.
- * \sa
- * - \ref ECLIC_GetCtrlIRQ_S
- */
- __STATIC_FORCEINLINE void __ECLIC_SetCtrlIRQ_S(IRQn_Type IRQn, uint8_t intctrl)
- {
- ECLIC->SCTRL[IRQn].INTCTRL = intctrl;
- }
- /**
- * \brief Get ECLIC Interrupt Input Control Register value for a specific interrupt in supervisor mode
- * \details
- * This function modify ECLIC Interrupt Input Control register of the specific interrupt \em IRQn.
- * \param [in] IRQn Interrupt number
- * \return value of ECLIC Interrupt Input Control register
- * \remarks
- * - IRQn must not be negative.
- * \sa
- * - \ref ECLIC_SetCtrlIRQ_S
- */
- __STATIC_FORCEINLINE uint8_t __ECLIC_GetCtrlIRQ_S(IRQn_Type IRQn)
- {
- return (ECLIC->SCTRL[IRQn].INTCTRL);
- }
- /**
- * \brief Set ECLIC Interrupt level of a specific interrupt in supervisor mode
- * \details
- * This function set interrupt level of the specific interrupt \em IRQn.
- * \param [in] IRQn Interrupt number
- * \param [in] lvl_abs Interrupt level
- * \remarks
- * - IRQn must not be negative.
- * - If lvl_abs to be set is larger than the max level allowed, it will be force to be max level.
- * - When you set level value you need use clciinfo.nlbits to get the width of level.
- * Then we could know the maximum of level. CLICINTCTLBITS is how many total bits are
- * present in the CLICINTCTL register.
- * \sa
- * - \ref ECLIC_GetLevelIRQ_S
- */
- __STATIC_INLINE void __ECLIC_SetLevelIRQ_S(IRQn_Type IRQn, uint8_t lvl_abs)
- {
- uint8_t nlbits = __ECLIC_GetCfgNlbits();
- uint8_t intctlbits = (uint8_t)__ECLIC_INTCTLBITS;
- if (nlbits == 0) {
- return;
- }
- if (nlbits > intctlbits) {
- nlbits = intctlbits;
- }
- uint8_t maxlvl = ((1UL << nlbits) - 1);
- if (lvl_abs > maxlvl) {
- lvl_abs = maxlvl;
- }
- uint8_t lvl = lvl_abs << (ECLIC_MAX_NLBITS - nlbits);
- uint8_t cur_ctrl = __ECLIC_GetCtrlIRQ_S(IRQn);
- cur_ctrl = cur_ctrl << nlbits;
- cur_ctrl = cur_ctrl >> nlbits;
- __ECLIC_SetCtrlIRQ_S(IRQn, (cur_ctrl | lvl));
- }
- /**
- * \brief Get ECLIC Interrupt level of a specific interrupt
- * \details
- * This function get interrupt level of the specific interrupt \em IRQn.
- * \param [in] IRQn Interrupt number
- * \return Interrupt level
- * \remarks
- * - IRQn must not be negative.
- * \sa
- * - \ref ECLIC_SetLevelIRQ_S
- */
- __STATIC_INLINE uint8_t __ECLIC_GetLevelIRQ_S(IRQn_Type IRQn)
- {
- uint8_t nlbits = __ECLIC_GetCfgNlbits();
- uint8_t intctlbits = (uint8_t)__ECLIC_INTCTLBITS;
- if (nlbits == 0) {
- return 0;
- }
- if (nlbits > intctlbits) {
- nlbits = intctlbits;
- }
- uint8_t intctrl = __ECLIC_GetCtrlIRQ_S(IRQn);
- uint8_t lvl_abs = intctrl >> (ECLIC_MAX_NLBITS - nlbits);
- return lvl_abs;
- }
- /**
- * \brief Set ECLIC Interrupt priority of a specific interrupt in supervisor mode
- * \details
- * This function get interrupt priority of the specific interrupt \em IRQn.
- * \param [in] IRQn Interrupt number
- * \param [in] pri Interrupt priority
- * \remarks
- * - IRQn must not be negative.
- * - If pri to be set is larger than the max priority allowed, it will be force to be max priority.
- * - Priority width is CLICINTCTLBITS minus clciinfo.nlbits if clciinfo.nlbits
- * is less than CLICINTCTLBITS. Otherwise priority width is 0.
- * \sa
- * - \ref ECLIC_GetPriorityIRQ_S
- */
- __STATIC_INLINE void __ECLIC_SetPriorityIRQ_S(IRQn_Type IRQn, uint8_t pri)
- {
- uint8_t nlbits = __ECLIC_GetCfgNlbits();
- uint8_t intctlbits = (uint8_t)__ECLIC_INTCTLBITS;
- if (nlbits < intctlbits) {
- uint8_t maxpri = ((1UL << (intctlbits - nlbits)) - 1);
- if (pri > maxpri) {
- pri = maxpri;
- }
- pri = pri << (ECLIC_MAX_NLBITS - intctlbits);
- uint8_t mask = ((uint8_t)(-1)) >> intctlbits;
- pri = pri | mask;
- uint8_t cur_ctrl = __ECLIC_GetCtrlIRQ_S(IRQn);
- cur_ctrl = cur_ctrl >> (ECLIC_MAX_NLBITS - nlbits);
- cur_ctrl = cur_ctrl << (ECLIC_MAX_NLBITS - nlbits);
- __ECLIC_SetCtrlIRQ_S(IRQn, (cur_ctrl | pri));
- }
- }
- /**
- * \brief Get ECLIC Interrupt priority of a specific interrupt in supervisor mode
- * \details
- * This function get interrupt priority of the specific interrupt \em IRQn.
- * \param [in] IRQn Interrupt number
- * \return Interrupt priority
- * \remarks
- * - IRQn must not be negative.
- * \sa
- * - \ref ECLIC_SetPriorityIRQ_S
- */
- __STATIC_INLINE uint8_t __ECLIC_GetPriorityIRQ_S(IRQn_Type IRQn)
- {
- uint8_t nlbits = __ECLIC_GetCfgNlbits();
- uint8_t intctlbits = (uint8_t)__ECLIC_INTCTLBITS;
- if (nlbits < intctlbits) {
- uint8_t cur_ctrl = __ECLIC_GetCtrlIRQ_S(IRQn);
- uint8_t pri = cur_ctrl << nlbits;
- pri = pri >> nlbits;
- pri = pri >> (ECLIC_MAX_NLBITS - intctlbits);
- return pri;
- } else {
- return 0;
- }
- }
- /**
- * \brief Enable a specific interrupt in supervisor mode
- * \details
- * This function enables the specific interrupt \em IRQn.
- * \param [in] IRQn Interrupt number
- * \remarks
- * - IRQn must not be negative.
- * \sa
- * - \ref ECLIC_DisableIRQ
- */
- __STATIC_FORCEINLINE void __ECLIC_EnableIRQ_S(IRQn_Type IRQn)
- {
- ECLIC->SCTRL[IRQn].INTIE |= CLIC_INTIE_IE_Msk;
- }
- /**
- * \brief Get a specific interrupt enable status in supervisor mode
- * \details
- * This function returns the interrupt enable status for the specific interrupt \em IRQn in S MODE.
- * \param [in] IRQn Interrupt number
- * \returns
- * - 0 Interrupt is not masked
- * - 1 Interrupt is enabled
- * \remarks
- * - IRQn must not be negative.
- * \sa
- * - \ref ECLIC_EnableIRQ_S
- * - \ref ECLIC_DisableIRQ_S
- */
- __STATIC_FORCEINLINE uint8_t __ECLIC_GetEnableIRQ_S(IRQn_Type IRQn)
- {
- return ((uint8_t) (ECLIC->SCTRL[IRQn].INTIE) & CLIC_INTIE_IE_Msk);
- }
- /**
- * \brief Disable a specific interrupt in supervisor mode
- * \details
- * This function disables the specific interrupt \em IRQn.
- * \param [in] IRQn Number of the external interrupt to disable
- * \remarks
- * - IRQn must not be negative.
- * \sa
- * - \ref ECLIC_EnableIRQ
- */
- __STATIC_FORCEINLINE void __ECLIC_DisableIRQ_S(IRQn_Type IRQn)
- {
- ECLIC->SCTRL[IRQn].INTIE &= ~CLIC_INTIE_IE_Msk;
- }
- /**
- * \brief Set Interrupt Vector of a specific interrupt in supervisor mode
- * \details
- * This function set interrupt handler address of the specific interrupt \em IRQn.
- * \param [in] IRQn Interrupt number
- * \param [in] vector Interrupt handler address
- * \remarks
- * - IRQn must not be negative.
- * - You can set the \ref CSR_CSR_MTVT to set interrupt vector table entry address.
- * - If your vector table is placed in readonly section, the vector for IRQn will not be modified.
- * For this case, you need to use the correct irq handler name defined in your vector table as
- * your irq handler function name.
- * - This function will only work correctly when the vector table is placed in an read-write enabled section.
- * \sa
- * - \ref ECLIC_GetVector_S
- */
- __STATIC_INLINE void __ECLIC_SetVector_S(IRQn_Type IRQn, rv_csr_t vector)
- {
- volatile unsigned long vec_base;
- vec_base = ((unsigned long)__RV_CSR_READ(CSR_STVT));
- vec_base += ((unsigned long)IRQn) * sizeof(unsigned long);
- (* (unsigned long *) vec_base) = vector;
- #if (defined(__DCACHE_PRESENT) && (__DCACHE_PRESENT == 1))
- #if (defined(__CCM_PRESENT) && (__CCM_PRESENT == 1))
- SFlushDCacheLine((unsigned long)vec_base);
- #endif
- #endif
- #if (defined(__ICACHE_PRESENT) && (__ICACHE_PRESENT == 1))
- #if (defined(__CCM_PRESENT) && (__CCM_PRESENT == 1))
- SInvalICacheLine((unsigned long)vec_base);
- #else
- __FENCE_I();
- #endif
- #endif
- }
- /**
- * \brief Get Interrupt Vector of a specific interrupt in supervisor mode
- * \details
- * This function get interrupt handler address of the specific interrupt \em IRQn.
- * \param [in] IRQn Interrupt number
- * \return Interrupt handler address
- * \remarks
- * - IRQn must not be negative.
- * - You can read \ref CSR_CSR_MTVT to get interrupt vector table entry address.
- * \sa
- * - \ref ECLIC_SMODE_SetVector
- */
- __STATIC_FORCEINLINE rv_csr_t __ECLIC_GetVector_S(IRQn_Type IRQn)
- {
- #if __RISCV_XLEN == 32
- return (*(uint32_t *)(__RV_CSR_READ(CSR_STVT) + IRQn * 4));
- #elif __RISCV_XLEN == 64
- return (*(uint64_t *)(__RV_CSR_READ(CSR_STVT) + IRQn * 8));
- #else // TODO Need cover for XLEN=128 case in future
- return (*(uint64_t *)(__RV_CSR_READ(CSR_STVT) + IRQn * 8));
- #endif
- }
- #if __ECLIC_VER == 2
- /**
- * \brief Enable ECLIC Shadow Register Function (Supervisor Mode)
- * \details
- * This function enables the shadow register function for ECLIC in Supervisor Mode.
- * It sets the SECLIC_CTL_SHADOW_EN bit in the CSR_SECLIC_CTL CSR.
- * This function is only valid for ECLIC version 2 and above in TEE environments.
- * \remarks
- * - API only available for ECLIC v2
- * \sa
- * - \ref __ECLIC_DisableShadow_S
- */
- __STATIC_FORCEINLINE void __ECLIC_EnableShadow_S(void)
- {
- __RV_CSR_SET(CSR_SECLIC_CTL, SECLIC_CTL_SHADOW_EN);
- }
- /**
- * \brief Disable ECLIC Shadow Register Function (Supervisor Mode)
- * \details
- * This function disables the shadow register function for ECLIC in Supervisor Mode.
- * It clears the SECLIC_CTL_SHADOW_EN bit in the CSR_SECLIC_CTL CSR.
- * This function is only valid for ECLIC version 2 and above in TEE environments.
- * \remarks
- * - API only available for ECLIC v2
- * \sa
- * - \ref __ECLIC_EnableShadow_S
- */
- __STATIC_FORCEINLINE void __ECLIC_DisableShadow_S(void)
- {
- __RV_CSR_CLEAR(CSR_SECLIC_CTL, SECLIC_CTL_SHADOW_EN);
- }
- /**
- * \brief Set Shadow Register Interrupt Level for a specific s-mode shadow register
- * \details
- * This function sets the interrupt level for a specific s-mode shadow register \em idx + 1.
- * It configures CSR_SSHADGPRLVL0 and CSR_SSHADGPRLVL1 registers.
- * \param [in] idx Shadow register index (0-7), corresponding to shadow registers 1-8
- * (Note: shadow register 0 is fixed for first-come-first-served s-mode
- * interrupt and cannot be configured)
- * \param [in] level Interrupt level to set for the shadow register
- * \remarks
- * - API only available for ECLIC v2
- * - idx = 0 means set SHAD1_CFG, which configures the shadow register 1
- * - For RV64, all 8 shadow registers are configured in CSR_SSHADGPRLVL0
- * - For RV32, shadow registers 1-4 are in lower 32 bits of CSR_SSHADGPRLVL0,
- * and shadow registers 5-8 are in CSR_SSHADGPRLVL1
- * \sa
- * - \ref ECLIC_GetShadowLevel_S
- */
- __STATIC_INLINE void __ECLIC_SetShadowLevel_S(unsigned long idx, uint8_t level)
- {
- /* Check if idx is valid (0-7) */
- if (idx > 7) {
- return;
- }
- uint8_t nlbits = (uint8_t)__ECLIC_GetCfgNlbits();
- /* Limit the level value to the available number of bits */
- uint8_t max_level = (1U << nlbits) - 1;
- if (level > max_level) {
- level = max_level;
- }
- /* Position the level value in the upper nlbits of the 8-bit field and set the low (8-nlbits) bits to 1 */
- uint8_t level_shifted = (uint8_t)((level << (8 - nlbits)) | ((1U << (8 - nlbits)) - 1));
- #if __RISCV_XLEN == 64
- /* For RV64, all 8 shadow registers are in CSR_SSHADGPRLVL0 */
- /* Calculate the bit position for the 8-bit field of the specified index */
- uint32_t bit_pos = idx << 3; /* idx * 8 using bit shift */
- /* Create mask to clear the 8-bit field for the specified index */
- uint64_t mask = (uint64_t)0xFFUL << bit_pos;
- /* Read, modify, and write the CSR register */
- uint64_t current_val = __RV_CSR_READ(CSR_SSHADGPRLVL0);
- current_val = (current_val & ~mask) | (((uint64_t)level_shifted) << bit_pos);
- __RV_CSR_WRITE(CSR_SSHADGPRLVL0, current_val);
- #else
- /* For RV32, calculate bit position and select appropriate register */
- if (idx < 4) {
- /* Shadow registers 1-4 are in CSR_SSHADGPRLVL0 */
- uint32_t bit_pos = idx << 3; /* idx * 8 using bit shift */
- uint32_t mask = 0xFFUL << bit_pos;
- uint32_t current_val = __RV_CSR_READ(CSR_SSHADGPRLVL0);
- current_val = (current_val & ~mask) | (((uint32_t)level_shifted) << bit_pos);
- __RV_CSR_WRITE(CSR_SSHADGPRLVL0, current_val);
- } else {
- /* Shadow registers 5-8 are in CSR_SSHADGPRLVL1 */
- uint32_t bit_pos = (idx - 4) << 3; /* (idx - 4) * 8 using bit shift */
- uint32_t mask = 0xFFUL << bit_pos;
- uint32_t current_val = __RV_CSR_READ(CSR_SSHADGPRLVL1);
- current_val = (current_val & ~mask) | (((uint32_t)level_shifted) << bit_pos);
- __RV_CSR_WRITE(CSR_SSHADGPRLVL1, current_val);
- }
- #endif
- }
- /**
- * \brief Get Shadow Register Interrupt Level for a specific s-mode shadow register
- * \details
- * This function gets the interrupt level for a specific s-mode shadow register \em idx + 1.
- * It reads CSR_SSHADGPRLVL0 and CSR_SSHADGPRLVL1 registers.
- * \param [in] idx Shadow register index (0-7), corresponding to shadow registers 1-8
- * (Note: shadow register 0 is fixed for first-come-first-served s-mode
- * interrupt and cannot be configured)
- * \return Interrupt level of the shadow register
- * \remarks
- * - API only available for ECLIC v2
- * - idx = 0 means set SHAD1_CFG, which configures the shadow register 1
- * - For RV64, all 8 shadow registers are configured in CSR_SSHADGPRLVL0
- * - For RV32, shadow registers 1-4 are in lower 32 bits of CSR_SSHADGPRLVL0,
- * and shadow registers 5-8 are in CSR_SSHADGPRLVL1
- * \sa
- * - \ref ECLIC_SetShadowLevel_S
- */
- __STATIC_INLINE uint8_t __ECLIC_GetShadowLevel_S(unsigned long idx)
- {
- /* Check if idx is valid (0-7) */
- if (idx > 7) {
- return 0;
- }
- uint8_t nlbits = (uint8_t)__ECLIC_GetCfgNlbits();
- #if __RISCV_XLEN == 64
- /* For RV64, all 8 shadow registers are in CSR_SSHADGPRLVL0 */
- /* Calculate the bit position for the 8-bit field of the specified index */
- uint32_t bit_pos = idx << 3; /* idx * 8 using bit shift */
- /* Read the CSR register and extract the 8-bit field */
- uint64_t current_val = __RV_CSR_READ(CSR_SSHADGPRLVL0);
- uint8_t extracted_val = (uint8_t)((current_val >> bit_pos) & 0xFF);
- /* Extract the level from the upper nlbits of the 8-bit field */
- uint8_t level = (extracted_val >> (8 - nlbits));
- return level;
- #else
- /* For RV32, calculate bit position and select appropriate register */
- if (idx < 4) {
- /* Shadow registers 1-4 are in CSR_SSHADGPRLVL0 */
- uint32_t bit_pos = idx << 3; /* idx * 8 using bit shift */
- /* Read the CSR register and extract the 8-bit field */
- uint32_t current_val = __RV_CSR_READ(CSR_SSHADGPRLVL0);
- uint8_t extracted_val = (uint8_t)((current_val >> bit_pos) & 0xFF);
- /* Extract the level from the upper nlbits of the 8-bit field */
- uint8_t level = (extracted_val >> (8 - nlbits));
- return level;
- } else {
- /* Shadow registers 5-8 are in CSR_SSHADGPRLVL1 */
- uint32_t bit_pos = (idx - 4) << 3; /* (idx - 4) * 8 using bit shift */
- /* Read the CSR register and extract the 8-bit field */
- uint32_t current_val = __RV_CSR_READ(CSR_SSHADGPRLVL1);
- uint8_t extracted_val = (uint8_t)((current_val >> bit_pos) & 0xFF);
- /* Extract the level from the upper nlbits of the 8-bit field */
- uint8_t level = (extracted_val >> (8 - nlbits));
- return level;
- }
- #endif
- }
- /**
- * \brief Set Shadow Register Level Register for s-mode
- * \details
- * This function sets the entire shadow register level register for s-mode.
- * It writes directly to CSR_SSHADGPRLVL0 register (and CSR_SSHADGPRLVL1 for RV32).
- * \param [in] value 64-bit value to set for the shadow register level register
- * \remarks
- * - API only available for ECLIC v2
- * - For RV64, all 8 shadow registers are configured in CSR_SSHADGPRLVL0
- * - For RV32, shadow registers 1-4 are in lower 32 bits of CSR_SSHADGPRLVL0,
- * and shadow registers 5-8 are in CSR_SSHADGPRLVL1
- * - Note: shadow register 0 is fixed for first-come-first-served s-mode interrupt and cannot be configured
- * \sa
- * - \ref ECLIC_GetShadowLevelReg_S
- */
- __STATIC_INLINE void __ECLIC_SetShadowLevelReg_S(uint64_t value)
- {
- #if __RISCV_XLEN == 64
- __RV_CSR_WRITE(CSR_SSHADGPRLVL0, value);
- #else
- __RV_CSR_WRITE(CSR_SSHADGPRLVL0, (uint32_t)value);
- __RV_CSR_WRITE(CSR_SSHADGPRLVL1, (uint32_t)(value >> 32));
- #endif
- }
- /**
- * \brief Get Shadow Register Level Register for s-mode
- * \details
- * This function gets the entire shadow register level register for s-mode.
- * It reads from CSR_SSHADGPRLVL0 register (and CSR_SSHADGPRLVL1 for RV32) and combines them.
- * \return 64-bit value of the shadow register level register
- * \remarks
- * - API only available for ECLIC v2
- * - For RV64, all 8 shadow registers are configured in CSR_SSHADGPRLVL0
- * - For RV32, shadow registers 1-4 are in lower 32 bits of CSR_SSHADGPRLVL0,
- * and shadow registers 5-8 are in CSR_SSHADGPRLVL1
- * - Note: shadow register 0 is fixed for first-come-first-served s-mode interrupt and cannot be configured
- * \sa
- * - \ref ECLIC_SetShadowLevelReg_S
- */
- __STATIC_INLINE uint64_t __ECLIC_GetShadowLevelReg_S(void)
- {
- #if __RISCV_XLEN == 64
- return __RV_CSR_READ(CSR_SSHADGPRLVL0);
- #else
- uint64_t value = __RV_CSR_READ(CSR_SSHADGPRLVL1);
- value <<= 32;
- value |= __RV_CSR_READ(CSR_SSHADGPRLVL0);
- return value;
- #endif
- }
- #endif
- #endif /* defined(__TEE_PRESENT) && (__TEE_PRESENT == 1) */
- /**
- * \brief Set Exception entry address
- * \details
- * This function set exception handler address to 'CSR_MTVEC'.
- * \param [in] addr Exception handler address
- * \remarks
- * - This function use to set exception handler address to 'CSR_MTVEC'.
- * Address need to be aligned to 64 bytes.
- * \sa
- * - \ref __get_exc_entry
- */
- __STATIC_FORCEINLINE void __set_exc_entry(rv_csr_t addr)
- {
- addr &= (rv_csr_t)(~0x3F);
- addr |= ECLIC_MODE_MTVEC_Msk;
- __RV_CSR_WRITE(CSR_MTVEC, addr);
- }
- /**
- * \brief Get Exception entry address
- * \details
- * This function get exception handler address from 'CSR_MTVEC'.
- * \return Exception handler address
- * \remarks
- * - This function use to get exception handler address from 'CSR_MTVEC'.
- * Address need to be aligned to 64 bytes.
- * \sa
- * - \ref __set_exc_entry
- */
- __STATIC_FORCEINLINE rv_csr_t __get_exc_entry(void)
- {
- unsigned long addr = __RV_CSR_READ(CSR_MTVEC);
- return (addr & ~ECLIC_MODE_MTVEC_Msk);
- }
- /**
- * \brief Set Non-vector interrupt entry address
- * \details
- * This function set Non-vector interrupt address.
- * \param [in] addr Non-vector interrupt entry address
- * \remarks
- * - This function use to set non-vector interrupt entry address to 'CSR_MTVT2' if
- * - CSR_MTVT2 bit0 is 1. If 'CSR_MTVT2' bit0 is 0 then set address to 'CSR_MTVEC'
- * \sa
- * - \ref __get_nonvec_entry
- */
- __STATIC_INLINE void __set_nonvec_entry(rv_csr_t addr)
- {
- if (__RV_CSR_READ(CSR_MTVT2) & 0x1) {
- __RV_CSR_WRITE(CSR_MTVT2, addr | 0x01);
- } else {
- addr &= (rv_csr_t)(~0x3F);
- addr |= ECLIC_MODE_MTVEC_Msk;
- __RV_CSR_WRITE(CSR_MTVEC, addr);
- }
- }
- /**
- * \brief Get Non-vector interrupt entry address
- * \details
- * This function get Non-vector interrupt address.
- * \return Non-vector interrupt handler address
- * \remarks
- * - This function use to get non-vector interrupt entry address from 'CSR_MTVT2' if
- * - CSR_MTVT2 bit0 is 1. If 'CSR_MTVT2' bit0 is 0 then get address from 'CSR_MTVEC'.
- * \sa
- * - \ref __set_nonvec_entry
- */
- __STATIC_INLINE rv_csr_t __get_nonvec_entry(void)
- {
- if (__RV_CSR_READ(CSR_MTVT2) & 0x1) {
- return __RV_CSR_READ(CSR_MTVT2) & (~(rv_csr_t)(0x1));
- } else {
- rv_csr_t addr = __RV_CSR_READ(CSR_MTVEC);
- return (addr & ~ECLIC_MODE_MTVEC_Msk);
- }
- }
- /**
- * \brief Get NMI interrupt entry from 'CSR_MNVEC'
- * \details
- * This function get NMI interrupt address from 'CSR_MNVEC'.
- * \return NMI interrupt handler address
- * \remarks
- * - This function use to get NMI interrupt handler address from 'CSR_MNVEC'. If CSR_MMISC_CTL[9] = 1 'CSR_MNVEC'
- * - will be equal as mtvec. If CSR_MMISC_CTL[9] = 0 'CSR_MNVEC' will be equal as reset vector.
- * - NMI entry is defined via \ref CSR_MMISC_CTL, writing to \ref CSR_MNVEC will be ignored.
- */
- __STATIC_FORCEINLINE rv_csr_t __get_nmi_entry(void)
- {
- return __RV_CSR_READ(CSR_MNVEC);
- }
- /* NOTE: SSUBM CSR is introduced in ECLIC v2, without this the S_Mode vector interrupt nesting
- * and non-vector interrupt nesting will not work properly */
- #if __ECLIC_VER == 2
- #define SAVE_SSUBM_VAR() rv_csr_t __ssubm = __RV_CSR_READ(CSR_SSUBM);
- #define RESTORE_SSUBM_VAR() __RV_CSR_WRITE(CSR_SSUBM, __ssubm);
- #else
- #define SAVE_SSUBM_VAR()
- #define RESTORE_SSUBM_VAR()
- #endif
- /**
- * \brief Save necessary CSRs into variables for vector interrupt nesting
- * \details
- * This macro is used to declare variables which are used for saving
- * CSRs(MCAUSE, MEPC, MSUB), and it will read these CSR content into
- * these variables, it need to be used in a vector-interrupt if nesting
- * is required.
- * \remarks
- * - Interrupt will be enabled after this macro is called
- * - It need to be used together with \ref RESTORE_IRQ_CSR_CONTEXT
- * - Don't use variable names __mcause, __mpec, __msubm in your ISR code
- * - If you want to enable interrupt nesting feature for vector interrupt,
- * you can do it like this:
- * \code
- * // __INTERRUPT attribute will generates function entry and exit sequences suitable
- * // for use in an interrupt handler when this attribute is present
- * __INTERRUPT void eclic_mtip_handler(void)
- * {
- * // Must call this to save CSRs
- * SAVE_IRQ_CSR_CONTEXT();
- * // !!!Interrupt is enabled here!!!
- * // !!!Higher priority interrupt could nest it!!!
- *
- * // put you own interrupt handling code here
- *
- * // Must call this to restore CSRs
- * RESTORE_IRQ_CSR_CONTEXT();
- * }
- * \endcode
- */
- #define SAVE_IRQ_CSR_CONTEXT() \
- rv_csr_t __mcause = __RV_CSR_READ(CSR_MCAUSE); \
- rv_csr_t __mepc = __RV_CSR_READ(CSR_MEPC); \
- rv_csr_t __msubm = __RV_CSR_READ(CSR_MSUBM); \
- __enable_irq();
- /*! Save necessary CSRs into variables for vector interrupt nesting in supervisor mode */
- #define SAVE_IRQ_CSR_CONTEXT_S() \
- rv_csr_t __scause = __RV_CSR_READ(CSR_SCAUSE); \
- rv_csr_t __sepc = __RV_CSR_READ(CSR_SEPC); \
- SAVE_SSUBM_VAR(); \
- __enable_irq_s();
- /**
- * \brief Restore necessary CSRs from variables for vector interrupt nesting
- * \details
- * This macro is used restore CSRs(MCAUSE, MEPC, MSUB) from pre-defined variables
- * in \ref SAVE_IRQ_CSR_CONTEXT macro.
- * \remarks
- * - Interrupt will be disabled after this macro is called
- * - It need to be used together with \ref SAVE_IRQ_CSR_CONTEXT
- */
- #define RESTORE_IRQ_CSR_CONTEXT() \
- __disable_irq(); \
- __RV_CSR_WRITE(CSR_MSUBM, __msubm); \
- __RV_CSR_WRITE(CSR_MEPC, __mepc); \
- __RV_CSR_WRITE(CSR_MCAUSE, __mcause);
- /*! Restore necessary CSRs from variables for vector interrupt nesting in supervisor mode */
- #define RESTORE_IRQ_CSR_CONTEXT_S() \
- __disable_irq_s(); \
- RESTORE_SSUBM_VAR(); \
- __RV_CSR_WRITE(CSR_SEPC, __sepc); \
- __RV_CSR_WRITE(CSR_SCAUSE, __scause);
- /** @} */ /* End of Doxygen Group NMSIS_Core_IntExc */
- #endif /* defined(__ECLIC_PRESENT) && (__ECLIC_PRESENT == 1) */
- #ifdef __cplusplus
- }
- #endif
- #endif /* __CORE_FEATURE_ECLIC__ */
|