/** * Copyright (c) 2024 Wei-Lun Hsu. All Rights Reserved. */ /** @file system_dev.h * * @author Wei-Lun Hsu * @version 0.1 * @date 2024/08/29 * @license * @description */ #ifndef __system_dev_H_wjaCXWfu_lqsX_H0XR_svyC_uj3MxJR5UZzV__ #define __system_dev_H_wjaCXWfu_lqsX_H0XR_svyC_uj3MxJR5UZzV__ #ifdef __cplusplus extern "C" { #endif #include #include //============================================================================= // Constant Definition //============================================================================= #ifndef SYS_TIMER_FREQ #define SYS_TIMER_FREQ 32768ul #endif #ifndef SYS_MAX_DELAY #define SYS_MAX_DELAY 0x7FFFFFFFul #endif #define SYS_IGNORE_TAG (~0) /** * Exception Code */ typedef enum EXCPn { /* =============== Nuclei N/NX Specific Exception Code =============== */ EXCPn_InsUnalign = 0, /*!< Instruction address misaligned */ EXCPn_InsAccFault = 1, /*!< Instruction access fault */ EXCPn_IlleIns = 2, /*!< Illegal instruction */ EXCPn_Break = 3, /*!< Beakpoint */ EXCPn_LdAddrUnalign = 4, /*!< Load address misaligned */ EXCPn_LdFault = 5, /*!< Load access fault */ EXCPn_StAddrUnalign = 6, /*!< Store or AMO address misaligned */ EXCPn_StAccessFault = 7, /*!< Store or AMO access fault */ EXCPn_UmodeEcall = 8, /*!< Environment call from User mode */ EXCPn_SmodeEcall = 9, /*!< Environment call from S-mode */ EXCPn_MmodeEcall = 11, /*!< Environment call from Machine mode */ #if 1 EXCPn_Total, #else EXCPn_InsPageFault = 12, /*!< Instruction page fault */ EXCPn_LdPageFault = 13, /*!< Load page fault */ EXCPn_StPageFault = 15, /*!< Store or AMO page fault */ EXCPn_StackOverflow = 24, /*!< Stack overflow fault */ EXCPn_StackUnderflow = 25, /*!< Stack underflow fault */ EXCPn_Total, #endif EXCPn_NMI = 0xfff, /*!< NMI interrupt */ } EXCPn_Type; /** * SYS_TIMER_PERIOD with 1ms, 10ms, 100ms */ typedef enum sys_tick { SYS_TICK_1_MS = 0, SYS_TICK_10_MS, SYS_TICK_100_MS, SYS_TICK_1_SEC, } sys_tick_t; #if defined(__ECLIC_PRESENT) && (__ECLIC_PRESENT == 1) typedef enum sys_irq_trigger { SYS_IRQ_TRIGGER_LEVEL = ECLIC_LEVEL_TRIGGER, /*!< Level Triggerred */ SYS_IRQ_TRIGGER_POSTIVE_EDGE = ECLIC_POSTIVE_EDGE_TRIGGER, /*!< Postive/Rising Edge Triggered */ SYS_IRQ_TRIGGER_NEGTIVE_EDGE = ECLIC_NEGTIVE_EDGE_TRIGGER, /*!< Negtive/Falling Edge Triggered */ SYS_IRQ_TRIGGER_MAX = ECLIC_MAX_TRIGGER, /*!< MAX Supported Trigger Mode */ } sys_irq_trigger_t; typedef enum sys_irq_level { SYS_IRQ_LEVEL_LL = 0, /*!< Interrupt Level lowest */ SYS_IRQ_LEVEL_L = 1, /*!< Interrupt Level low */ SYS_IRQ_LEVEL_M = 2, /*!< Interrupt Level midden */ SYS_IRQ_LEVEL_H = 3, /*!< Interrupt Level high */ SYS_IRQ_LEVEL_HH = 4, /*!< Interrupt Level highest */ } sys_irq_level_t; typedef enum sys_irq_priority { SYS_IRQ_PRIORITY_LOW = 0, /*!< Interrupt Priority Low */ SYS_IRQ_PRIORITY_MIDDEN = 1, /*!< Interrupt Priority Midden */ SYS_IRQ_PRIORITY_HIGH = 2, /*!< Interrupt Priority High */ } sys_irq_priority_t; #endif /* __ECLIC_PRESENT */ typedef void (*fp_isr_t)(void); /** * Exception Handler Function Typedef */ typedef void (*cb_excp_handler_t)(uint32_t cause, uint32_t sp); //============================================================================= // Macro Definition //============================================================================= /** * Locate function to specific section * e.g. * uint32_t __FASTCODE foo(void) { return 123; } */ #define __FASTCODE __attribute__((__section__(".fastcode"))) __STATIC_FORCEINLINE uint32_t* __get_pc(void) { uint32_t *pc; __asm__("auipc %0, 0" : "=r"(pc)); return pc; } __STATIC_FORCEINLINE uint32_t* __get_sp(void) { uint32_t *sp; __asm__("move %0, sp" : "=r"(sp)); return sp; } //============================================================================= // Structure Definition //============================================================================= typedef struct excp_frame { uint32_t ra; /* ra: x1, return address for jump */ uint32_t tp; /* tp: x4, thread pointer */ uint32_t t0; /* t0: x5, temporary register 0 */ uint32_t t1; /* t1: x6, temporary register 1 */ uint32_t t2; /* t2: x7, temporary register 2 */ uint32_t a0; /* a0: x10, return value or function argument 0 */ uint32_t a1; /* a1: x11, return value or function argument 1 */ uint32_t a2; /* a2: x12, function argument 2 */ uint32_t a3; /* a3: x13, function argument 3 */ uint32_t a4; /* a4: x14, function argument 4 */ uint32_t a5; /* a5: x15, function argument 5 */ uint32_t cause; /* cause: machine cause csr register */ uint32_t epc; /* epc: machine exception program counter csr register */ uint32_t msubm; /* msubm: machine sub-mode csr register, nuclei customized */ } excp_frame_t; typedef struct sys_irq_attr { uint8_t trig_mode; /*!< the interrupt trigger mode, @ref sys_irq_trigger_t */ uint8_t disable_vector; /*!< use vector table or not */ uint8_t level; /*!< interupt nested level, high-level (bigger value) will interrupt low-level, @ref sys_irq_level_t */ uint8_t priority; /*!< interrupt priority, the priority of the pended interrupts (when the same IRQ level), @ref sys_irq_priority_t ps. This priority has NOTHING about nested interrup */ } sys_irq_attr_t; //============================================================================= // Global Data Definition //============================================================================= extern volatile uint32_t g_SystemCoreClock; /*!< System Clock Frequency (Core Clock) */ extern volatile uint32_t g_SysTicks; extern volatile uint32_t g_SysTickPeriod; extern volatile uint32_t g_SysTickUnit_MS; //============================================================================= // Private Function Definition //============================================================================= //============================================================================= // Public Function Definition //============================================================================= /** * \brief Enable system tick */ __STATIC_FORCEINLINE void sys_enable_systick(void) { SysTick_Reload(g_SysTickPeriod); ECLIC_EnableIRQ(SysTimer_IRQn); SysTimer_Start(); return; } /** * \brief Disable system tick */ __STATIC_FORCEINLINE void sys_disable_systick(void) { ECLIC_DisableIRQ(SysTimer_IRQn); SysTimer_Stop(); return; } /** * \brief Trigger software interrupt through system timer * * \return None */ __STATIC_FORCEINLINE void sys_launch_swi(void) { SysTimer_SetSWIRQ(); return; } /** * \brief Clear software interrupt * * \return None */ __STATIC_FORCEINLINE void sys_clear_swi(void) { SysTimer_ClearSWIRQ(); return; } /** * \brief Clear interrupt flags of interrupt controller * * \param [in] irq_id the target IRQ Id, @ref IRQn_Type * \return None */ __STATIC_FORCEINLINE void sys_clear_IRQFlag(IRQn_Type irq_id) { ECLIC_ClearPendingIRQ(irq_id); return; } /** * \brief Get the pending specific interrupt of interrupt controller * * \param [in] irq_id the target IRQ Id, @ref IRQn_Type * \return * IRQ is pending or not * */ __STATIC_FORCEINLINE int sys_get_IRQPending(IRQn_Type irq_id) { return ECLIC_GetPendingIRQ(irq_id); } /** * \brief Get system ticks * * \return * System Ticks */ __STATIC_FORCEINLINE uint32_t sys_get_tick(void) { return g_SysTicks; } /** * \brief Open interrupt source of interrupt controller * * \param [in] irq_id the target IRQ Id, @ref IRQn_Type * \return None */ __STATIC_FORCEINLINE void sys_open_IRQ(IRQn_Type irq_id) { ECLIC_EnableIRQ(irq_id); return; } /** * \brief Close interrupt source of interrupt controller * * \param [in] irq_id the target IRQ Id, @ref IRQn_Type * \return None */ __STATIC_FORCEINLINE void sys_close_IRQ(IRQn_Type irq_id) { ECLIC_DisableIRQ(irq_id); return; } /** * \brief Enable global interrupt * * \return None */ __STATIC_FORCEINLINE void sys_enable_girq(void) { __enable_irq(); return; } /** * \brief Disable global interrupt * * \return None */ __STATIC_FORCEINLINE void sys_disable_girq(void) { __disable_irq(); return; } /** * \brief system high accuracy delay with systick * * \param [in] msec milli-seconds * \return None */ void sys_delay(uint32_t msec); /** * \brief system low accuracy delay with the CPU tick * * \param [in] ticks the CPU ticks * \return None */ void sys_busy_wait(uint32_t ticks); /** * \brief get system frequency * * \return the cpu frequency value */ uint32_t sys_get_cpu_freq(void); #if defined(__EXCP_PRESENT) && (__EXCP_PRESENT == 1) /** * \brief Register handler to Exception table * * \param [in] excp_id exception ID, @ref EXCPn_Type * \param [in] excp_handler the handler function * \return * 0 : ok * others: fail */ int sys_excp_register_handler(EXCPn_Type excp_id, uint32_t excp_handler); #endif #if defined(__ECLIC_PRESENT) && (__ECLIC_PRESENT == 1) /** * \brief Set the attribute of the target interrupt * * \param [in] irq_id the terget IRQ ID, @ref IRQn_Type * \param [in] pAttr pointer to a attribute of interrupt if necessary, @ref sys_irq_attr_t * \return * 0 : ok * others: fail */ int sys_set_IRQAttr(IRQn_Type irq_id, sys_irq_attr_t *pAttr); /** * \brief Register ISR to Interrupt * * \param [in] irq_id the terget IRQ ID, @ref IRQn_Type * \param [in] cb_handler the ISR funciotn * \param [in] pAttr pointer to a attribute of interrupt if necessary, @ref sys_irq_attr_t * \return * 0 : ok * others: fail */ int sys_register_IRQ(IRQn_Type irq_id, void *cb_handler, sys_irq_attr_t *pAttr); #endif /* __ECLIC_PRESENT == 1 */ /** * \brief Configure system tick * * \param [in] ticks period of ticks * SYS_TICK_1_MS/ SYS_TICK_10_MS/ SYS_TICK_100_MS */ void sys_config_systick(uint32_t ticks); #ifdef __cplusplus } #endif #endif