diff options
Diffstat (limited to 'include/rtems/score/nios2-utility.h')
-rw-r--r-- | include/rtems/score/nios2-utility.h | 516 |
1 files changed, 516 insertions, 0 deletions
diff --git a/include/rtems/score/nios2-utility.h b/include/rtems/score/nios2-utility.h new file mode 100644 index 0000000000..d5eb4b3597 --- /dev/null +++ b/include/rtems/score/nios2-utility.h @@ -0,0 +1,516 @@ +/** + * @file + * + * @brief NIOS II Utility + */ +/* + * Copyright (c) 2011 embedded brains GmbH. All rights reserved. + * + * embedded brains GmbH + * Obere Lagerstr. 30 + * 82178 Puchheim + * Germany + * <rtems@embedded-brains.de> + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.org/license/LICENSE. + */ + +#ifndef _RTEMS_SCORE_NIOS2_UTILITY_H +#define _RTEMS_SCORE_NIOS2_UTILITY_H + +#define NIOS2_CTLREG_INDEX_STATUS 0 +#define NIOS2_CTLREG_INDEX_ESTATUS 1 +#define NIOS2_CTLREG_INDEX_BSTATUS 2 +#define NIOS2_CTLREG_INDEX_IENABLE 3 +#define NIOS2_CTLREG_INDEX_IPENDING 4 +#define NIOS2_CTLREG_INDEX_CPUID 5 +#define NIOS2_CTLREG_INDEX_EXCEPTION 7 +#define NIOS2_CTLREG_INDEX_PTEADDR 8 +#define NIOS2_CTLREG_INDEX_TLBACC 9 +#define NIOS2_CTLREG_INDEX_TLBMISC 10 +#define NIOS2_CTLREG_INDEX_BADADDR 12 +#define NIOS2_CTLREG_INDEX_CONFIG 13 +#define NIOS2_CTLREG_INDEX_MPUBASE 14 +#define NIOS2_CTLREG_INDEX_MPUACC 15 + +#define NIOS2_CONTEXT_OFFSET_R16 0 +#define NIOS2_CONTEXT_OFFSET_R17 4 +#define NIOS2_CONTEXT_OFFSET_R18 8 +#define NIOS2_CONTEXT_OFFSET_R19 12 +#define NIOS2_CONTEXT_OFFSET_R20 16 +#define NIOS2_CONTEXT_OFFSET_R21 20 +#define NIOS2_CONTEXT_OFFSET_R22 24 +#define NIOS2_CONTEXT_OFFSET_R23 28 +#define NIOS2_CONTEXT_OFFSET_FP 32 +#define NIOS2_CONTEXT_OFFSET_STATUS 36 +#define NIOS2_CONTEXT_OFFSET_SP 40 +#define NIOS2_CONTEXT_OFFSET_RA 44 +#define NIOS2_CONTEXT_OFFSET_THREAD_DISPATCH_DISABLED 48 +#define NIOS2_CONTEXT_OFFSET_STACK_MPUBASE 52 +#define NIOS2_CONTEXT_OFFSET_STACK_MPUACC 56 + +#define NIOS2_ISR_STATUS_MASK_IIC 0xfffffffe +#define NIOS2_ISR_STATUS_BITS_IIC 0x00000000 + +#define NIOS2_ISR_STATUS_MASK_EIC_IL 0xfffffc0f +#define NIOS2_ISR_STATUS_BITS_EIC_IL 0x000003f0 + +#define NIOS2_ISR_STATUS_MASK_EIC_RSIE 0xf7ffffff +#define NIOS2_ISR_STATUS_BITS_EIC_RSIE 0x00000000 + +#define NIOS2_STATUS_RSIE (1 << 23) +#define NIOS2_STATUS_NMI (1 << 22) +#define NIOS2_STATUS_PRS_OFFSET 16 +#define NIOS2_STATUS_PRS_MASK (0x3f << NIOS2_STATUS_PRS_OFFSET) +#define NIOS2_STATUS_CRS_OFFSET 10 +#define NIOS2_STATUS_CRS_MASK (0x3f << NIOS2_STATUS_CRS_OFFSET) +#define NIOS2_STATUS_IL_OFFSET 4 +#define NIOS2_STATUS_IL_MASK (0x3f << NIOS2_STATUS_IL_OFFSET) +#define NIOS2_STATUS_IH (1 << 3) +#define NIOS2_STATUS_EH (1 << 2) +#define NIOS2_STATUS_U (1 << 1) +#define NIOS2_STATUS_PIE (1 << 0) + +#define NIOS2_EXCEPTION_CAUSE_OFFSET 2 +#define NIOS2_EXCEPTION_CAUSE_MASK (0x1f << NIOS2_EXCEPTION_CAUSE_OFFSET) + +#define NIOS2_PTEADDR_PTBASE_OFFSET 22 +#define NIOS2_PTEADDR_PTBASE_MASK (0x3ff << NIOS2_PTEADDR_PTBASE_OFFSET) +#define NIOS2_PTEADDR_VPN_OFFSET 2 +#define NIOS2_PTEADDR_VPN_MASK (0xfffff << NIOS2_PTEADDR_VPN_OFFSET) + +#define NIOS2_TLBACC_IG_OFFSET 25 +#define NIOS2_TLBACC_IG_MASK (0x3ff << NIOS2_TLBACC_IG_OFFSET) +#define NIOS2_TLBACC_C (1 << 24) +#define NIOS2_TLBACC_R (1 << 23) +#define NIOS2_TLBACC_W (1 << 22) +#define NIOS2_TLBACC_X (1 << 21) +#define NIOS2_TLBACC_G (1 << 20) +#define NIOS2_TLBACC_PFN_OFFSET 2 +#define NIOS2_TLBACC_PFN_MASK (0xfffff << NIOS2_TLBACC_PFN_OFFSET) + +#define NIOS2_TLBMISC_WAY_OFFSET 20 +#define NIOS2_TLBMISC_WAY_MASK (0xf << NIOS2_TLBMISC_WAY_OFFSET) +#define NIOS2_TLBMISC_RD (1 << 19) +#define NIOS2_TLBMISC_WE (1 << 18) +#define NIOS2_TLBMISC_PID_OFFSET 5 +#define NIOS2_TLBMISC_PID_MASK (0x3fff << NIOS2_TLBMISC_PID_OFFSET) +#define NIOS2_TLBMISC_DBL (1 << 3) +#define NIOS2_TLBMISC_BAD (1 << 2) +#define NIOS2_TLBMISC_PERM (1 << 1) +#define NIOS2_TLBMISC_D (1 << 0) + +#define NIOS2_CONFIG_ANI (1 << 1) +#define NIOS2_CONFIG_PE (1 << 0) + +#define NIOS2_MPUBASE_BASE_OFFSET 6 +#define NIOS2_MPUBASE_BASE_MASK (0x1ffffff << NIOS2_MPUBASE_BASE_OFFSET) +#define NIOS2_MPUBASE_INDEX_OFFSET 1 + +/* Avoid redefines with Altera HAL */ +#define NIOS2_MPUBASE_INDEX_MASK (0x0000003e) + +#define NIOS2_MPUBASE_D (1 << 0) + +#define NIOS2_MPUACC_MASK_OFFSET 6 + +/* Avoid redefines with Altera HAL */ +#define NIOS2_MPUACC_MASK_MASK (0x7fffffc0) + +#define NIOS2_MPUACC_LIMIT_OFFSET 6 + +/* Avoid redefines with Altera HAL */ +#define NIOS2_MPUACC_LIMIT_MASK (0xffffffc0) + +#define NIOS2_MPUACC_C (1 << 5) +#define NIOS2_MPUACC_PERM_OFFSET 2 + +/* Avoid redefines with Altera HAL */ +#define NIOS2_MPUACC_PERM_MASK (0x0000001c) + +#define NIOS2_MPUACC_RD (1 << 1) +#define NIOS2_MPUACC_WR (1 << 0) + +#ifndef ASM + +#include <stddef.h> +#include <stdint.h> +#include <stdbool.h> + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/** + * @brief Nios II specific thread dispatch disabled indicator. + * + * This global variable is used by the interrupt dispatch support for the + * external interrupt controller (EIC) with shadow registers. This makes it + * possible to do the thread dispatch after an interrupt without disabled + * interrupts and thus probably reduce the maximum interrupt latency. Its + * purpose is to prevent unbounded stack usage of the interrupted thread. + */ +extern uint32_t _Nios2_Thread_dispatch_disabled; + +/** + * @brief This global symbol specifies the status register mask used to disable + * interrupts. + * + * The board support package must provide a global symbol with this name to + * specify the status register mask used in _CPU_ISR_Disable(). + */ +extern char _Nios2_ISR_Status_mask []; + +/** + * @brief This symbol specifies the status register bits used to disable + * interrupts. + * + * The board support package must provide a global symbol with this name to + * specify the status register bits used in _CPU_ISR_Disable(). + */ +extern char _Nios2_ISR_Status_bits []; + +static inline void _Nios2_Flush_pipeline( void ) +{ + __asm__ volatile ("flushp"); +} + +static inline uint32_t _Nios2_Get_ctlreg_status( void ) +{ + return (uint32_t) __builtin_rdctl( NIOS2_CTLREG_INDEX_STATUS ); +} + +static inline void _Nios2_Set_ctlreg_status( uint32_t value ) +{ + __builtin_wrctl( NIOS2_CTLREG_INDEX_STATUS, (int) value ); +} + +static inline uint32_t _Nios2_Get_ctlreg_estatus( void ) +{ + return (uint32_t) __builtin_rdctl( NIOS2_CTLREG_INDEX_ESTATUS ); +} + +static inline void _Nios2_Set_ctlreg_estatus( uint32_t value ) +{ + __builtin_wrctl( NIOS2_CTLREG_INDEX_ESTATUS, (int) value ); +} + +static inline uint32_t _Nios2_Get_ctlreg_bstatus( void ) +{ + return (uint32_t) __builtin_rdctl( NIOS2_CTLREG_INDEX_BSTATUS ); +} + +static inline void _Nios2_Set_ctlreg_bstatus( uint32_t value ) +{ + __builtin_wrctl( NIOS2_CTLREG_INDEX_BSTATUS, (int) value ); +} + +static inline uint32_t _Nios2_Get_ctlreg_ienable( void ) +{ + return (uint32_t) __builtin_rdctl( NIOS2_CTLREG_INDEX_IENABLE ); +} + +static inline void _Nios2_Set_ctlreg_ienable( uint32_t value ) +{ + __builtin_wrctl( NIOS2_CTLREG_INDEX_IENABLE, (int) value ); +} + +static inline uint32_t _Nios2_Get_ctlreg_ipending( void ) +{ + return (uint32_t) __builtin_rdctl( NIOS2_CTLREG_INDEX_IPENDING ); +} + +static inline uint32_t _Nios2_Get_ctlreg_cpuid( void ) +{ + return (uint32_t) __builtin_rdctl( NIOS2_CTLREG_INDEX_CPUID ); +} + +static inline uint32_t _Nios2_Get_ctlreg_exception( void ) +{ + return (uint32_t) __builtin_rdctl( NIOS2_CTLREG_INDEX_EXCEPTION ); +} + +static inline uint32_t _Nios2_Get_ctlreg_pteaddr( void ) +{ + return (uint32_t) __builtin_rdctl( NIOS2_CTLREG_INDEX_PTEADDR ); +} + +static inline void _Nios2_Set_ctlreg_pteaddr( uint32_t value ) +{ + __builtin_wrctl( NIOS2_CTLREG_INDEX_PTEADDR, (int) value ); +} + +static inline uint32_t _Nios2_Get_ctlreg_tlbacc( void ) +{ + return (uint32_t) __builtin_rdctl( NIOS2_CTLREG_INDEX_TLBACC ); +} + +static inline void _Nios2_Set_ctlreg_tlbacc( uint32_t value ) +{ + __builtin_wrctl( NIOS2_CTLREG_INDEX_TLBACC, (int) value ); +} + +static inline uint32_t _Nios2_Get_ctlreg_tlbmisc( void ) +{ + return (uint32_t) __builtin_rdctl( NIOS2_CTLREG_INDEX_TLBMISC ); +} + +static inline void _Nios2_Set_ctlreg_tlbmisc( uint32_t value ) +{ + __builtin_wrctl( NIOS2_CTLREG_INDEX_TLBMISC, (int) value ); +} + +static inline uint32_t _Nios2_Get_ctlreg_badaddr( void ) +{ + return (uint32_t) __builtin_rdctl( NIOS2_CTLREG_INDEX_BADADDR ); +} + +static inline uint32_t _Nios2_Get_ctlreg_config( void ) +{ + return (uint32_t) __builtin_rdctl( NIOS2_CTLREG_INDEX_CONFIG ); +} + +static inline void _Nios2_Set_ctlreg_config( uint32_t value ) +{ + __builtin_wrctl( NIOS2_CTLREG_INDEX_CONFIG, (int) value ); +} + +static inline uint32_t _Nios2_Get_ctlreg_mpubase( void ) +{ + return (uint32_t) __builtin_rdctl( NIOS2_CTLREG_INDEX_MPUBASE ); +} + +static inline void _Nios2_Set_ctlreg_mpubase( uint32_t value ) +{ + __builtin_wrctl( NIOS2_CTLREG_INDEX_MPUBASE, (int) value ); +} + +static inline uint32_t _Nios2_Get_ctlreg_mpuacc( void ) +{ + return (uint32_t) __builtin_rdctl( NIOS2_CTLREG_INDEX_MPUACC ); +} + +static inline void _Nios2_Set_ctlreg_mpuacc( uint32_t value ) +{ + __builtin_wrctl( NIOS2_CTLREG_INDEX_MPUACC, (int) value ); +} + +static inline uint32_t _Nios2_ISR_Get_status_mask( void ) +{ + return (uint32_t) &_Nios2_ISR_Status_mask [0]; +} + +static inline uint32_t _Nios2_ISR_Get_status_bits( void ) +{ + return (uint32_t) &_Nios2_ISR_Status_bits [0]; +} + +static inline bool _Nios2_Has_internal_interrupt_controller( void ) +{ + return _Nios2_ISR_Get_status_mask() == NIOS2_ISR_STATUS_MASK_IIC; +} + +uint32_t _Nios2_ISR_Set_level( uint32_t new_level, uint32_t status ); + +typedef struct { + int data_address_width; + int instruction_address_width; + int data_region_size_log2; + int instruction_region_size_log2; + int data_region_count; + int instruction_region_count; + int data_index_for_stack_protection; + bool region_uses_limit; + bool enable_data_cache_for_stack; +} Nios2_MPU_Configuration; + +void _Nios2_MPU_Set_configuration( const Nios2_MPU_Configuration *config ); + +const Nios2_MPU_Configuration *_Nios2_MPU_Get_configuration( void ); + +typedef enum { + NIOS2_MPU_INST_PERM_SVR_NONE_USER_NONE = 0, + NIOS2_MPU_INST_PERM_SVR_EXECUTE_USER_NONE, + NIOS2_MPU_INST_PERM_SVR_EXECUTE_USER_EXECUTE, + NIOS2_MPU_DATA_PERM_SVR_NONE_USER_NONE = 0, + NIOS2_MPU_DATA_PERM_SVR_READONLY_USER_NONE, + NIOS2_MPU_DATA_PERM_SVR_READONLY_USER_READONLY, + NIOS2_MPU_DATA_PERM_SVR_READWRITE_USER_NONE = 4, + NIOS2_MPU_DATA_PERM_SVR_READWRITE_USER_READONLY, + NIOS2_MPU_DATA_PERM_SVR_READWRITE_USER_READWRITE +} Nios2_MPU_Region_permissions; + +typedef struct { + int index; + const void *base; + const void *end; + Nios2_MPU_Region_permissions perm; + bool data; + bool cacheable; + bool read; + bool write; +} Nios2_MPU_Region_descriptor; + +#define NIOS2_MPU_REGION_DESC_INST( index, base, end ) \ + { \ + (index), (base), (end), NIOS2_MPU_INST_PERM_SVR_EXECUTE_USER_NONE, \ + false, false, false, true \ + } + +#define NIOS2_MPU_REGION_DESC_DATA_RO( index, base, end ) \ + { \ + (index), (base), (end), NIOS2_MPU_DATA_PERM_SVR_READONLY_USER_NONE, \ + true, true, false, true \ + } + +#define NIOS2_MPU_REGION_DESC_DATA_RW( index, base, end ) \ + { \ + (index), (base), (end), NIOS2_MPU_DATA_PERM_SVR_READWRITE_USER_NONE, \ + true, true, false, true \ + } + +#define NIOS2_MPU_REGION_DESC_DATA_IO( index, base, end ) \ + { \ + (index), (base), (end), NIOS2_MPU_DATA_PERM_SVR_READWRITE_USER_NONE, \ + true, false, false, true \ + } + +static inline int _Nios2_MPU_Get_region_count( + const Nios2_MPU_Configuration *config, + bool data +) +{ + return data ? + config->data_region_count + : config->instruction_region_count; +} + +static inline bool _Nios2_MPU_Is_valid_index( + const Nios2_MPU_Configuration *config, + int index, + bool data +) +{ + return 0 <= index + && index < _Nios2_MPU_Get_region_count( config, data ); +} + +bool _Nios2_MPU_Setup_region_registers( + const Nios2_MPU_Configuration *config, + const Nios2_MPU_Region_descriptor *desc, + uint32_t *mpubase, + uint32_t *mpuacc +); + +bool _Nios2_MPU_Get_region_descriptor( + const Nios2_MPU_Configuration *config, + int index, + bool data, + Nios2_MPU_Region_descriptor *desc +); + +/** + * @brief Searches the region table part for a disabled region. + * + * The table will be searched between indices @a begin and @a end. The @a end + * index is not part of the search range. If @a end is negative, then the + * region count will be used. Thus a @a begin of 0 and a @a end of -1 will + * specify the complete table. + * + * @retval -1 No disabled region is available. + * @retval other Index of disabled region. + */ +int _Nios2_MPU_Get_disabled_region_index( + const Nios2_MPU_Configuration *config, + bool data, + int begin, + int end +); + +/** + * @brief Adds a region according to region descriptor @a desc. + * + * If @a force is true, then an enabled region will be overwritten. + * + * @retval true Successful operation. + * @retval false Invalid region descriptor or region already in use. + */ +bool _Nios2_MPU_Add_region( + const Nios2_MPU_Configuration *config, + const Nios2_MPU_Region_descriptor *desc, + bool force +); + +static inline void _Nios2_MPU_Get_region_registers( + int index, + bool data, + uint32_t *mpubase, + uint32_t *mpuacc +) +{ + uint32_t base = (uint32_t) + (((index << NIOS2_MPUBASE_INDEX_OFFSET) & NIOS2_MPUBASE_INDEX_MASK) + | (data ? NIOS2_MPUBASE_D : 0)); + + _Nios2_Set_ctlreg_mpubase( base ); + _Nios2_Set_ctlreg_mpuacc( NIOS2_MPUACC_RD ); + _Nios2_Flush_pipeline(); + *mpubase = _Nios2_Get_ctlreg_mpubase() | base; + *mpuacc = _Nios2_Get_ctlreg_mpuacc(); +} + +static inline void _Nios2_MPU_Set_region_registers( + uint32_t mpubase, + uint32_t mpuacc +) +{ + _Nios2_Set_ctlreg_mpubase( mpubase ); + _Nios2_Set_ctlreg_mpuacc( mpuacc ); + _Nios2_Flush_pipeline(); +} + +static inline void _Nios2_MPU_Enable( void ) +{ + uint32_t config = _Nios2_Get_ctlreg_config(); + + _Nios2_Set_ctlreg_config( config | NIOS2_CONFIG_PE ); +} + +static inline uint32_t _Nios2_MPU_Disable( void ) +{ + uint32_t config = _Nios2_Get_ctlreg_config(); + uint32_t config_pe = NIOS2_CONFIG_PE; + + _Nios2_Set_ctlreg_config( config & ~config_pe ); + + return config; +} + +static inline void _Nios2_MPU_Restore( uint32_t config ) +{ + _Nios2_Set_ctlreg_config( config ); +} + +uint32_t _Nios2_MPU_Disable_protected( void ); + +void _Nios2_MPU_Reset( const Nios2_MPU_Configuration *config ); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#else /* ASM */ + + .macro NIOS2_ASM_DISABLE_INTERRUPTS new_status, current_status + movhi \new_status, %hiadj(_Nios2_ISR_Status_mask) + addi \new_status, \new_status, %lo(_Nios2_ISR_Status_mask) + and \new_status, \current_status, \new_status + ori \new_status, \new_status, %lo(_Nios2_ISR_Status_bits) + wrctl status, \new_status + .endm + +#endif /* ASM */ + +#endif /* _RTEMS_SCORE_NIOS2_UTILITY_H */ |