/**
* @file
*
*/
/*
* Copyright (c) 2018 embedded brains GmbH
*
* Copyright (c) 2015 University of York.
* Hesham Almatary <hesham@alumni.york.ac.uk>
*
* COPYRIGHT (c) 1989-1999.
* On-Line Applications Research Corporation (OAR).
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#ifndef _RISCV_CPU_H
#define _RISCV_CPU_H
#ifdef __cplusplus
extern "C" {
#endif
#include <rtems/score/basedefs.h>
#include <rtems/score/riscv.h>
#define RISCV_MSTATUS_MIE 0x8
#define CPU_ISR_PASSES_FRAME_POINTER FALSE
#define CPU_HARDWARE_FP FALSE
#define CPU_SOFTWARE_FP FALSE
#define CPU_ALL_TASKS_ARE_FP FALSE
#define CPU_IDLE_TASK_IS_FP FALSE
#define CPU_USE_DEFERRED_FP_SWITCH FALSE
#define CPU_ENABLE_ROBUST_THREAD_DISPATCH TRUE
#define CPU_STACK_GROWS_UP FALSE
#define CPU_STRUCTURE_ALIGNMENT __attribute__ ((aligned (64)))
#define CPU_BIG_ENDIAN FALSE
#define CPU_LITTLE_ENDIAN TRUE
#define CPU_MODES_INTERRUPT_MASK 0x0000000000000001
#define CPU_CACHE_LINE_BYTES 64
#if __riscv_xlen == 32
#define CPU_SIZEOF_POINTER 4
#define CPU_STACK_MINIMUM_SIZE 4096
#elif __riscv_xlen == 64
#define CPU_SIZEOF_POINTER 8
#define CPU_STACK_MINIMUM_SIZE 8192
#endif /* __riscv_xlen */
/* RISC-V ELF psABI specification */
#define CPU_ALIGNMENT 16
#define CPU_HEAP_ALIGNMENT CPU_ALIGNMENT
/* RISC-V ELF psABI specification */
#define CPU_STACK_ALIGNMENT 16
#define CPU_INTERRUPT_STACK_ALIGNMENT CPU_CACHE_LINE_BYTES
/*
* Processor defined structures required for cpukit/score.
*/
#ifndef ASM
#if __riscv_flen == 32
typedef float RISCV_Float;
#elif __riscv_flen == 64
typedef double RISCV_Float;
#endif
typedef struct {
#ifdef RTEMS_SMP
volatile uint32_t is_executing;
#else
uint32_t reserved;
#endif
uint32_t isr_dispatch_disable;
uintptr_t ra;
uintptr_t sp;
uintptr_t tp;
uintptr_t s0;
uintptr_t s1;
uintptr_t s2;
uintptr_t s3;
uintptr_t s4;
uintptr_t s5;
uintptr_t s6;
uintptr_t s7;
uintptr_t s8;
uintptr_t s9;
uintptr_t s10;
uintptr_t s11;
#if __riscv_flen > 0
uint32_t fcsr;
RISCV_Float fs0;
RISCV_Float fs1;
RISCV_Float fs2;
RISCV_Float fs3;
RISCV_Float fs4;
RISCV_Float fs5;
RISCV_Float fs6;
RISCV_Float fs7;
RISCV_Float fs8;
RISCV_Float fs9;
RISCV_Float fs10;
RISCV_Float fs11;
#endif
} Context_Control;
#define _CPU_Context_Get_SP( _context ) \
(_context)->sp
#define CPU_MPCI_RECEIVE_SERVER_EXTRA_STACK 0
#define CPU_PROVIDES_ISR_IS_IN_PROGRESS FALSE
static inline uint32_t riscv_interrupt_disable( void )
{
unsigned long mstatus;
__asm__ volatile (
".option push\n"
".option arch, +zicsr\n"
"csrrc %0, mstatus, " RTEMS_XSTRING( RISCV_MSTATUS_MIE ) "\n"
".option pop" :
"=&r" ( mstatus )
);
return mstatus & RISCV_MSTATUS_MIE;
}
static inline void riscv_interrupt_enable( uint32_t level )
{
__asm__ volatile (
".option push\n"
".option arch, +zicsr\n"
"csrrs zero, mstatus, %0\n"
".option pop" :
:
"r" ( level )
);
}
#define _CPU_ISR_Disable( _level ) \
_level = riscv_interrupt_disable()
#define _CPU_ISR_Enable( _level ) \
riscv_interrupt_enable( _level )
#define _CPU_ISR_Flash( _level ) \
do{ \
_CPU_ISR_Enable( _level ); \
riscv_interrupt_disable(); \
} while(0)
RTEMS_INLINE_ROUTINE bool _CPU_ISR_Is_enabled( unsigned long level )
{
return ( level & RISCV_MSTATUS_MIE ) != 0;
}
RTEMS_INLINE_ROUTINE void _CPU_ISR_Set_level( uint32_t level )
{
if ( ( level & CPU_MODES_INTERRUPT_MASK) == 0 ) {
__asm__ volatile (
".option push\n"
".option arch, +zicsr\n"
"csrrs zero, mstatus, " RTEMS_XSTRING( RISCV_MSTATUS_MIE ) "\n"
".option pop"
);
} else {
__asm__ volatile (
".option push\n"
".option arch, +zicsr\n"
"csrrc zero, mstatus, " RTEMS_XSTRING( RISCV_MSTATUS_MIE ) "\n"
".option pop"
);
}
}
uint32_t _CPU_ISR_Get_level( void );
/* end of ISR handler macros */
void _CPU_Context_Initialize(
Context_Control *context,
void *stack_area_begin,
size_t stack_area_size,
uint32_t new_level,
void ( *entry_point )( void ),
bool is_fp,
void *tls_area
);
#define _CPU_Context_Restart_self( _the_context ) \
_CPU_Context_restore( (_the_context) )
#define CPU_USE_GENERIC_BITFIELD_CODE TRUE
#define CPU_USE_GENERIC_BITFIELD_DATA TRUE
#define CPU_USE_LIBC_INIT_FINI_ARRAY TRUE
#define CPU_MAXIMUM_PROCESSORS 32
typedef uint16_t Priority_bit_map_Word;
/*
* See The RISC-V Instruction Set Manual, Volume II: RISC-V Privileged
* Architectures V1.10, Table 3.6: Machine cause register (mcause) values after
* trap.
*/
typedef enum {
RISCV_INTERRUPT_SOFTWARE_USER = 0,
RISCV_INTERRUPT_SOFTWARE_SUPERVISOR = 1,
RISCV_INTERRUPT_SOFTWARE_MACHINE = 3,
RISCV_INTERRUPT_TIMER_USER = 4,
RISCV_INTERRUPT_TIMER_SUPERVISOR = 5,
RISCV_INTERRUPT_TIMER_MACHINE = 7,
RISCV_INTERRUPT_EXTERNAL_USER = 8,
RISCV_INTERRUPT_EXTERNAL_SUPERVISOR = 9,
RISCV_INTERRUPT_EXTERNAL_MACHINE = 11
} RISCV_Interrupt_code;
/*
* See The RISC-V Instruction Set Manual, Volume II: RISC-V Privileged
* Architectures V1.10, Table 3.6: Machine cause register (mcause) values after
* trap.
*/
typedef enum {
RISCV_EXCEPTION_INSTRUCTION_ADDRESS_MISALIGNED = 0,
RISCV_EXCEPTION_INSTRUCTION_ACCESS_FAULT = 1,
RISCV_EXCEPTION_ILLEGAL_INSTRUCTION = 2,
RISCV_EXCEPTION_BREAKPOINT = 3,
RISCV_EXCEPTION_LOAD_ADDRESS_MISALIGNED = 4,
RISCV_EXCEPTION_LOAD_ACCESS_FAULT = 5,
RISCV_EXCEPTION_STORE_OR_AMO_ADDRESS_MISALIGNED = 6,
RISCV_EXCEPTION_STORE_OR_AMO_ACCESS_FAULT = 7,
RISCV_EXCEPTION_ENVIRONMENT_CALL_FROM_U_MODE = 8,
RISCV_EXCEPTION_ENVIRONMENT_CALL_FROM_S_MODE = 9,
RISCV_EXCEPTION_ENVIRONMENT_CALL_FROM_M_MODE = 11,
RISCV_EXCEPTION_INSTRUCTION_PAGE_FAULT = 12,
RISCV_EXCEPTION_LOAD_PAGE_FAULT = 13,
RISCV_EXCEPTION_STORE_OR_AMO_PAGE_FAULT = 15
} RISCV_Exception_code;
typedef struct {
uintptr_t mstatus;
uintptr_t mepc;
uintptr_t a2;
uintptr_t s0;
uintptr_t s1;
uintptr_t ra;
uintptr_t a3;
uintptr_t a4;
uintptr_t a5;
uintptr_t a6;
uintptr_t a7;
uintptr_t t0;
uintptr_t t1;
uintptr_t t2;
uintptr_t t3;
uintptr_t t4;
uintptr_t t5;
uintptr_t t6;
#if __riscv_flen > 0
uint32_t fcsr;
RISCV_Float ft0;
RISCV_Float ft1;
RISCV_Float ft2;
RISCV_Float ft3;
RISCV_Float ft4;
RISCV_Float ft5;
RISCV_Float ft6;
RISCV_Float ft7;
RISCV_Float ft8;
RISCV_Float ft9;
RISCV_Float ft10;
RISCV_Float ft11;
RISCV_Float fa0;
RISCV_Float fa1;
RISCV_Float fa2;
RISCV_Float fa3;
RISCV_Float fa4;
RISCV_Float fa5;
RISCV_Float fa6;
RISCV_Float fa7;
#endif
uintptr_t a0;
uintptr_t a1;
} RTEMS_ALIGNED( CPU_STACK_ALIGNMENT ) CPU_Interrupt_frame;
typedef struct {
CPU_Interrupt_frame Interrupt_frame;
uintptr_t mcause;
uintptr_t sp;
uintptr_t gp;
uintptr_t tp;
uintptr_t s2;
uintptr_t s3;
uintptr_t s4;
uintptr_t s5;
uintptr_t s6;
uintptr_t s7;
uintptr_t s8;
uintptr_t s9;
uintptr_t s10;
uintptr_t s11;
#if __riscv_flen > 0
RISCV_Float fs0;
RISCV_Float fs1;
RISCV_Float fs2;
RISCV_Float fs3;
RISCV_Float fs4;
RISCV_Float fs5;
RISCV_Float fs6;
RISCV_Float fs7;
RISCV_Float fs8;
RISCV_Float fs9;
RISCV_Float fs10;
RISCV_Float fs11;
#endif
} CPU_Exception_frame;
/**
* @brief Prints the exception frame via printk().
*
* @see rtems_fatal() and RTEMS_FATAL_SOURCE_EXCEPTION.
*/
void _CPU_Exception_frame_print( const CPU_Exception_frame *frame );
/* end of Priority handler macros */
/* functions */
/*
* _CPU_Initialize
*
* This routine performs CPU dependent initialization.
*
*/
void _CPU_Initialize(
void
);
void *_CPU_Thread_Idle_body( uintptr_t ignored );
/*
* _CPU_Context_switch
*
* This routine switches from the run context to the heir context.
*
* RISCV Specific Information:
*
* Please see the comments in the .c file for a description of how
* this function works. There are several things to be aware of.
*/
void _CPU_Context_switch(
Context_Control *run,
Context_Control *heir
);
RTEMS_NO_RETURN void _CPU_Context_switch_no_return(
Context_Control *executing,
Context_Control *heir
);
/*
* _CPU_Context_restore
*
* This routine is generally used only to restart self in an
* efficient manner. It may simply be a label in _CPU_Context_switch.
*
* NOTE: May be unnecessary to reload some registers.
*
*/
RTEMS_NO_RETURN void _CPU_Context_restore( Context_Control *new_context );
/* The following routine swaps the endian format of an unsigned int.
* It must be static because it is referenced indirectly.
*
* This version will work on any processor, but if there is a better
* way for your CPU PLEASE use it. The most common way to do this is to:
*
* swap least significant two bytes with 16-bit rotate
* swap upper and lower 16-bits
* swap most significant two bytes with 16-bit rotate
*
* Some CPUs have special instructions which swap a 32-bit quantity in
* a single instruction (e.g. i486). It is probably best to avoid
* an "endian swapping control bit" in the CPU. One good reason is
* that interrupts would probably have to be disabled to insure that
* an interrupt does not try to access the same "chunk" with the wrong
* endian. Another good reason is that on some CPUs, the endian bit
* endianness for ALL fetches -- both code and data -- so the code
* will be fetched incorrectly.
*
*/
static inline uint32_t CPU_swap_u32(
uint32_t value
)
{
uint32_t byte1, byte2, byte3, byte4, swapped;
byte4 = (value >> 24) & 0xff;
byte3 = (value >> 16) & 0xff;
byte2 = (value >> 8) & 0xff;
byte1 = value & 0xff;
swapped = (byte1 << 24) | (byte2 << 16) | (byte3 << 8) | byte4;
return ( swapped );
}
#define CPU_swap_u16( value ) \
(((value&0xff) << 8) | ((value >> 8)&0xff))
typedef uint32_t CPU_Counter_ticks;
uint32_t _CPU_Counter_frequency( void );
extern volatile uint32_t * const _RISCV_Counter;
CPU_Counter_ticks _CPU_Counter_read( void );
static inline CPU_Counter_ticks _CPU_Counter_difference(
CPU_Counter_ticks second,
CPU_Counter_ticks first
)
{
return second - first;
}
#ifdef RTEMS_SMP
uint32_t _CPU_SMP_Initialize( void );
bool _CPU_SMP_Start_processor( uint32_t cpu_index );
void _CPU_SMP_Finalize_initialization( uint32_t cpu_count );
void _CPU_SMP_Prepare_start_multitasking( void );
static inline uint32_t _CPU_SMP_Get_current_processor( void )
{
unsigned long mhartid;
__asm__ volatile (
".option push\n"
".option arch, +zicsr\n"
"csrr %0, mhartid\n"
".option pop" :
"=&r" ( mhartid )
);
return (uint32_t) mhartid;
}
void _CPU_SMP_Send_interrupt( uint32_t target_processor_index );
static inline bool _CPU_Context_Get_is_executing(
const Context_Control *context
)
{
return context->is_executing;
}
static inline void _CPU_Context_Set_is_executing(
Context_Control *context,
bool is_executing
)
{
context->is_executing = is_executing;
}
RTEMS_NO_RETURN void _RISCV_Start_multitasking( Context_Control *heir );
#define _CPU_Start_multitasking( _heir ) _RISCV_Start_multitasking( _heir )
#endif /* RTEMS_SMP */
/** Type that can store a 32-bit integer or a pointer. */
typedef uintptr_t CPU_Uint32ptr;
#endif /* ASM */
#ifdef __cplusplus
}
#endif
#endif