diff --git a/rtos/pmsis/pmsis_api/include/pmsis/chips/default_cv32e40p.h b/rtos/pmsis/pmsis_api/include/pmsis/chips/default_cv32e40p.h new file mode 100644 index 00000000..bf6e8f09 --- /dev/null +++ b/rtos/pmsis/pmsis_api/include/pmsis/chips/default_cv32e40p.h @@ -0,0 +1,87 @@ +/* + * Copyright (C) 2020 GreenWaves Technologies + * + * 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 + * + * http://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 __PMSIS_CHIPS_DEFAULT_H__ +#define __PMSIS_CHIPS_DEFAULT_H__ + +/** + * \ingroup groupChips + */ + +/** + * \enum pi_pad_e + * \brief Pad numbers. + * + * This is used to identify pads. + */ +typedef enum +{ + PI_PAD_NONE +} pi_pad_e; + +/** + * \enum pi_gpio_e + * \brief GPIO numbers. + * + * List of available GPIO pins. + */ +typedef enum +{ + PI_GPIO_NONE +} pi_gpio_e; + +/** \enum pi_perf_event_e + * \brief Performance event identifiers. + * + * This can be used to describe which performance event to monitor (cycles, + * cache miss, etc). + */ +typedef enum { + PI_PERF_CYCLES = 17, /*!< Total number of cycles (also includes the + cycles where the core is sleeping). Be careful that this event is using a + timer shared within the cluster, so resetting, starting or stopping it on + one core will impact other cores of the same cluster. */ + PI_PERF_ACTIVE_CYCLES = 0, /*!< Counts the number of cycles the core was + active (not sleeping). */ + PI_PERF_INSTR = 1, /*!< Counts the number of instructions executed. + */ + PI_PERF_LD_STALL = 2, /*!< Number of load data hazards. */ + PI_PERF_JR_STALL = 3, /*!< Number of jump register data hazards. */ + PI_PERF_IMISS = 4, /*!< Cycles waiting for instruction fetches, i.e. + number of instructions wasted due to non-ideal caching. */ + PI_PERF_LD = 5, /*!< Number of data memory loads executed. + Misaligned accesses are counted twice. */ + PI_PERF_ST = 6, /*!< Number of data memory stores executed. + Misaligned accesses are counted twice. */ + PI_PERF_JUMP = 7, /*!< Number of unconditional jumps (j, jal, jr, + jalr). */ + PI_PERF_BRANCH = 8, /*!< Number of branches. Counts both taken and + not taken branches. */ + PI_PERF_BTAKEN = 9, /*!< Number of taken branches. */ + PI_PERF_RVC = 10, /*!< Number of compressed instructions + executed. */ + PI_PIPE_STALL = 11, /*!< Number of cycles from stalled pipeline. */ + PI_APU_TYPE = 12, /*!< Number of type conflicts on APU/FP. */ + PI_APU_CONT = 13, /*!< Number of contentions on APU/FP. */ + PI_APU_DEP = 14, /*!< Number of dependency stall on APU/FP. */ + PI_APU_WB = 15 /*!< Number of write backs on APU/FP. */ +} pi_perf_event_e; + +/** + * @} + */ + +#endif /* __PMSIS_CHIPS_GAP9_PAD_H__ */ diff --git a/rtos/pulpos/common/include/pmsis.h b/rtos/pulpos/common/include/pmsis.h index cc380eb1..5472b401 100644 --- a/rtos/pulpos/common/include/pmsis.h +++ b/rtos/pulpos/common/include/pmsis.h @@ -14,7 +14,7 @@ * limitations under the License. */ -/* +/* * Authors: Germain Haugou, GreenWaves Technologies (germain.haugou@greenwaves-technologies.com) */ @@ -39,6 +39,8 @@ #elif defined(__GAP9__) #include "pmsis/chips/gap9/pad.h" #include "pmsis/chips/gap9/gpio.h" +#elif defined(ARCHI_HAS_COREV) +#include "pmsis/chips/default_cv32e40p.h" #else #include "pmsis/chips/default.h" #endif @@ -76,4 +78,3 @@ #include #endif - diff --git a/rtos/pulpos/common/include/pos/implem/perf.h b/rtos/pulpos/common/include/pos/implem/perf.h index 359a2bc5..19e8e3d6 100644 --- a/rtos/pulpos/common/include/pos/implem/perf.h +++ b/rtos/pulpos/common/include/pos/implem/perf.h @@ -37,7 +37,11 @@ static inline void pi_perf_cl_reset() { #ifdef ARCHI_HAS_CLUSTER timer_reset(timer_base_cl(0, 0, 0)); + #ifndef ARCHI_HAS_COREV cpu_perf_setall(0); + #else + cpu_perf_setall(MCOUNTINHIBIT_RESET); // 0xFFFF_FFFD resets performance counters in cv32e40p (mcountinhibit, processor specs pag. 43) + #endif #endif } @@ -45,7 +49,11 @@ static inline void pi_perf_fc_reset() { #ifdef ARCHI_HAS_FC timer_reset(timer_base_fc(0, 0)); + #ifndef ARCHI_HAS_COREV cpu_perf_setall(0); + #else + cpu_perf_setall(MCOUNTINHIBIT_RESET); // 0xFFFF_FFFD resets performance counters in cv32e40p (mcountinhibit, processor specs pag. 43) + #endif #endif } @@ -61,7 +69,11 @@ static inline void pi_perf_cl_start() { #ifdef ARCHI_HAS_CLUSTER timer_start(timer_base_cl(0, 0, 0)); + #ifndef ARCHI_HAS_COREV cpu_perf_conf(PCMR_ACTIVE | PCMR_SATURATE); + #else + cpu_perf_conf(MCOUNTINHIBIT_ACTIVE); + #endif #endif } @@ -69,7 +81,11 @@ static inline void pi_perf_fc_start() { #ifdef ARCHI_HAS_FC timer_start(timer_base_fc(0, 0)); + #ifndef ARCHI_HAS_COREV cpu_perf_conf(PCMR_ACTIVE | PCMR_SATURATE); + #else + cpu_perf_conf(MCOUNTINHIBIT_ACTIVE); + #endif #endif } @@ -85,7 +101,11 @@ static inline void pi_perf_cl_stop() { #ifdef ARCHI_HAS_CLUSTER timer_conf_set(timer_base_cl(0, 0, 0), TIMER_CFG_LO_ENABLE(0)); + #ifndef ARCHI_HAS_COREV cpu_perf_conf(0); + #else + cpu_perf_conf(MCOUNTINHIBIT_RESET); + #endif #endif } @@ -105,6 +125,7 @@ static inline void pi_perf_stop() pi_perf_cl_stop(); } +// get mhpmcounter{4, 31} events count with NUM_MHPMCOUNTERS = 16 static inline unsigned int pi_perf_cl_read(int event) { #ifdef ARCHI_HAS_CLUSTER @@ -114,7 +135,11 @@ static inline unsigned int pi_perf_cl_read(int event) } else { - return cpu_perf_get(event); +#if __PLATFORM__ != ARCHI_PLATFORM_BOARD + return cpu_perf_get(1 + event); +#else + return cpu_perf_get(0); +#endif } #else return 0; @@ -130,7 +155,11 @@ static inline unsigned int pi_perf_fc_read(int event) } else { - return cpu_perf_get(event); +#if __PLATFORM__ != ARCHI_PLATFORM_BOARD + return cpu_perf_get(1 + event); +#else + return cpu_perf_get(0); +#endif } #else return 0; @@ -145,6 +174,67 @@ static inline unsigned int pi_perf_read(int event) return pi_perf_cl_read(event); } + +#ifdef ARCHI_HAS_COREV + +// CV32E40P-specific API functions for handling Performance Counters reads + +// Get clock cycle count from mcycle counter +static inline unsigned int pi_perf_cl_read_mcycle() +{ +#ifdef ARCHI_HAS_CLUSTER + return cpu_perf_get_mcycle(); +#else + return 0; +#endif +} + +static inline unsigned int pi_perf_fc_read_mcycle() +{ +#ifdef ARCHI_HAS_FC + return cpu_perf_get_mcycle(); +#else + return 0; +#endif +} + +static inline unsigned int pi_perf_read_mcycle() +{ + if (hal_is_fc()) + return pi_perf_fc_read_mcycle(); + else + return pi_perf_cl_read_mcycle(); +} + + +// Get instructions count from minstret counter +static inline unsigned int pi_perf_cl_read_minstret() +{ +#ifdef ARCHI_HAS_CLUSTER + return cpu_perf_get_minstret(); +#else + return 0; +#endif +} + +static inline unsigned int pi_perf_fc_read_minstret() +{ +#ifdef ARCHI_HAS_FC + return cpu_perf_get_minstret(); +#else + return 0; +#endif +} + +static inline unsigned int pi_perf_read_minstret() +{ + if (hal_is_fc()) + return pi_perf_fc_read_minstret(); + else + return pi_perf_cl_read_minstret(); +} +#endif + #endif /// @endcond diff --git a/rtos/pulpos/common/kernel/crt0.S b/rtos/pulpos/common/kernel/crt0.S index d22ce131..30228cd2 100644 --- a/rtos/pulpos/common/kernel/crt0.S +++ b/rtos/pulpos/common/kernel/crt0.S @@ -21,7 +21,7 @@ #include "archi/pulp.h" .section .text_l2 -#ifdef ARCHI_HAS_COREV +#if defined(ARCHI_HAS_COREV) && (!defined(__PULP_TOOLCHAIN__) && defined(__COREV_TOOLCHAIN__)) .attribute arch, "rv32imc_xcorev2p0" #endif .global pos_init_entry diff --git a/rtos/pulpos/common/kernel/irq_asm.S b/rtos/pulpos/common/kernel/irq_asm.S index 2c520281..304f9c12 100644 --- a/rtos/pulpos/common/kernel/irq_asm.S +++ b/rtos/pulpos/common/kernel/irq_asm.S @@ -20,7 +20,7 @@ .section .text_l2 -#ifdef ARCHI_HAS_COREV +#if defined(ARCHI_HAS_COREV) && (!defined(__PULP_TOOLCHAIN__) && defined(__COREV_TOOLCHAIN__)) .attribute arch, "rv32imc_xcorev2p0" #endif .global pos_irq_call_external_c_function diff --git a/rtos/pulpos/common/kernel/soc_event_eu.S b/rtos/pulpos/common/kernel/soc_event_eu.S index 39b8517c..c8b19746 100644 --- a/rtos/pulpos/common/kernel/soc_event_eu.S +++ b/rtos/pulpos/common/kernel/soc_event_eu.S @@ -14,7 +14,7 @@ # limitations under the License. # -# +# # Authors: Germain Haugou, GreenWaves Technologies (germain.haugou@greenwaves-technologies.com) # @@ -59,7 +59,7 @@ pos_soc_event_handler_asm: sw x9, 0(x10) # Extract ID part - #ifdef ARCHI_HAS_COREV + #if defined(ARCHI_HAS_COREV) && (!defined(__PULP_TOOLCHAIN__) && defined(__COREV_TOOLCHAIN__)) cv.extractur x10, x8, EU_SOC_EVENTS_EVENT_MASK_BITS-1, EU_SOC_EVENTS_EVENT_MASK_OFFSET #else p.extractu x10, x8, EU_SOC_EVENTS_EVENT_MASK_BITS-1, EU_SOC_EVENTS_EVENT_MASK_OFFSET @@ -139,8 +139,7 @@ pos_soc_event_store_asm: lw x12, %tiny(pos_soc_event_status)(x11) andi x10, x10, 0x1f - #ifdef ARCHI_HAS_COREV - cv.bsetr x12, x12, x10 + #if defined(ARCHI_HAS_COREV) && (!defined(__PULP_TOOLCHAIN__) && defined(__COREV_TOOLCHAIN__)) cv.bsetr x12, x12, x10 #else p.bsetr x12, x12, x10 #endif diff --git a/rtos/pulpos/common/kernel/soc_event_v2_itc.S b/rtos/pulpos/common/kernel/soc_event_v2_itc.S index 91e3684e..2ee65607 100644 --- a/rtos/pulpos/common/kernel/soc_event_v2_itc.S +++ b/rtos/pulpos/common/kernel/soc_event_v2_itc.S @@ -14,7 +14,7 @@ # limitations under the License. # -# +# # Authors: Germain Haugou, GreenWaves Technologies (germain.haugou@greenwaves-technologies.com) # @@ -22,7 +22,7 @@ .section .text_l2 -#ifdef ARCHI_HAS_COREV +#if defined(ARCHI_HAS_COREV) && (!defined(__PULP_TOOLCHAIN__) && defined(__COREV_TOOLCHAIN__)) .attribute arch, "rv32imc_xcorev2p0" #endif @@ -77,13 +77,13 @@ lw x11, %tiny(pos_soc_event_callback_arg)(x11) #else la t0, pos_soc_event_callback -#ifdef ARCHI_HAS_COREV +#if defined(ARCHI_HAS_COREV) && (!defined(__PULP_TOOLCHAIN__) && defined(__COREV_TOOLCHAIN__)) cv.lw x12, t0(x11) #else p.lw x12, t0(x11) #endif /*ARCHI_HAS_COREV*/ la t0, pos_soc_event_callback_arg -#ifdef ARCHI_HAS_COREV +#if defined(ARCHI_HAS_COREV) && (!defined(__PULP_TOOLCHAIN__) && defined(__COREV_TOOLCHAIN__)) cv.lw x11, t0(x11) #else p.lw x11, t0(x11) @@ -112,14 +112,14 @@ pos_soc_event_store_asm: lw x12, %tiny(pos_soc_event_status)(x11) #else la t0, pos_soc_event_status -#ifdef ARCHI_HAS_COREV +#if defined(ARCHI_HAS_COREV) && (!defined(__PULP_TOOLCHAIN__) && defined(__COREV_TOOLCHAIN__)) cv.lw x12, t0(x11) #else p.lw x12, t0(x11) #endif /*ARCHI_HAS_COREV*/ #endif andi x10, x10, 0x1f -#ifdef ARCHI_HAS_COREV +#if defined(ARCHI_HAS_COREV) && (!defined(__PULP_TOOLCHAIN__) && defined(__COREV_TOOLCHAIN__)) li x11, 1 sll x11, x11, x10 or x12, x12, x11 @@ -132,7 +132,7 @@ pos_soc_event_store_asm: sw x12, %tiny(pos_soc_event_status)(x11) #else la t0, pos_soc_event_status -#ifdef ARCHI_HAS_COREV +#if defined(ARCHI_HAS_COREV) && (!defined(__PULP_TOOLCHAIN__) && defined(__COREV_TOOLCHAIN__)) cv.sw x12, t0(x11) #else p.sw x12, t0(x11) diff --git a/rtos/pulpos/common/kernel/task_asm.S b/rtos/pulpos/common/kernel/task_asm.S index c3913548..8ea8a3fa 100644 --- a/rtos/pulpos/common/kernel/task_asm.S +++ b/rtos/pulpos/common/kernel/task_asm.S @@ -22,7 +22,7 @@ .section .text_l2 -#ifdef ARCHI_HAS_COREV +#if defined(ARCHI_HAS_COREV) && (!defined(__PULP_TOOLCHAIN__) && defined(__COREV_TOOLCHAIN__)) .attribute arch, "rv32imc_xcorev2p0" #endif diff --git a/rtos/pulpos/common/kernel/time_asm.S b/rtos/pulpos/common/kernel/time_asm.S index 261db881..e273e4d3 100644 --- a/rtos/pulpos/common/kernel/time_asm.S +++ b/rtos/pulpos/common/kernel/time_asm.S @@ -22,7 +22,7 @@ .section .text_l2 -#ifdef ARCHI_HAS_COREV +#if defined(ARCHI_HAS_COREV) && (!defined(__PULP_TOOLCHAIN__) && defined(__COREV_TOOLCHAIN__)) .attribute arch, "rv32imc_xcorev2p0" #endif diff --git a/rtos/pulpos/pulp/drivers/cluster/pe-eu-v3.S b/rtos/pulpos/pulp/drivers/cluster/pe-eu-v3.S index 627e7556..1cb8bd6d 100644 --- a/rtos/pulpos/pulp/drivers/cluster/pe-eu-v3.S +++ b/rtos/pulpos/pulp/drivers/cluster/pe-eu-v3.S @@ -14,7 +14,7 @@ * limitations under the License. */ -/* +/* * Authors: Germain Haugou, GreenWaves Technologies (germain.haugou@greenwaves-technologies.com) */ @@ -22,7 +22,7 @@ .section .cluster.text , "ax" -#ifdef ARCHI_HAS_COREV +#if defined(ARCHI_HAS_COREV) && !defined(__PULP_TOOLCHAIN__) .attribute arch, "rv32imc_xcorev2p0" #endif @@ -146,7 +146,7 @@ pos_master_no_slave_barrier: // Set stack on slaves // For that we push first the function for setting stack, then the stack size and the base -#ifdef ARCHI_HAS_COREV +#if defined(ARCHI_HAS_COREV) && !defined(__PULP_TOOLCHAIN__) //cv.beqimm t5, 0, pos_master_loop_no_slave beqz t5, pos_master_loop_no_slave #else @@ -164,7 +164,7 @@ pos_master_loop_no_slave: pos_master_sleep: sw s4, EU_CORE_MASK_OR(s3) -#ifdef ARCHI_HAS_COREV +#if defined(ARCHI_HAS_COREV) && !defined(__PULP_TOOLCHAIN__) //cv.elw x0, EU_CORE_EVENT_WAIT_CLEAR(s3) lw x0, EU_CORE_EVENT_WAIT_CLEAR(s3) //beqz x0, hal_itc_wait_for_interrupt @@ -182,7 +182,7 @@ L10: pos_push_event_to_fc_wait: sw s4, EU_CORE_MASK_OR(s3) -#ifdef ARCHI_HAS_COREV +#if defined(ARCHI_HAS_COREV) && !defined(__PULP_TOOLCHAIN__) //cv.elw x0, EU_CORE_EVENT_WAIT_CLEAR(s3) lw x0, EU_CORE_EVENT_WAIT_CLEAR(s3) //beqz x0, hal_itc_wait_for_interrupt @@ -234,7 +234,7 @@ pos_fork_return: #ifdef ARCHI_HAS_CC // When the cluster has a controller barrier 0 is used for normal team barrier // and barrier 1 is used for end of offload -#ifdef ARCHI_HAS_COREV +#if defined(ARCHI_HAS_COREV) && (!defined(__PULP_TOOLCHAIN__) && defined(__COREV_TOOLCHAIN__)) //cv.elw t0, EU_BARRIER_DEMUX_OFFSET + EU_HW_BARR_TRIGGER_WAIT_CLEAR + EU_BARRIER_SIZE(s2) lw t0, EU_BARRIER_DEMUX_OFFSET + EU_HW_BARR_TRIGGER_WAIT_CLEAR + EU_BARRIER_SIZE(s2) //beqz t0, hal_itc_wait_for_interrupt @@ -245,7 +245,7 @@ L0: p.elw t0, EU_BARRIER_DEMUX_OFFSET + EU_HW_BARR_TRIGGER_WAIT_CLEAR + EU_BARRIER_SIZE(s2) #endif /*ARCHI_HAS_COREV*/ #else -#ifdef ARCHI_HAS_COREV +#if defined(ARCHI_HAS_COREV) && (!defined(__PULP_TOOLCHAIN__) && defined(__COREV_TOOLCHAIN__)) //cv.elw t0, EU_BARRIER_DEMUX_OFFSET + EU_HW_BARR_TRIGGER_WAIT_CLEAR(s2) lw t0, EU_BARRIER_DEMUX_OFFSET + EU_HW_BARR_TRIGGER_WAIT_CLEAR(s2) //beqz t0, hal_itc_wait_for_interrupt @@ -255,12 +255,12 @@ L1: #else p.elw t0, EU_BARRIER_DEMUX_OFFSET + EU_HW_BARR_TRIGGER_WAIT_CLEAR(s2) #endif /*ARCHI_HAS_COREV*/ -#endif +#endif pos_wait_for_dispatch: // Wait for PC + arg information from dispatcher -#ifdef ARCHI_HAS_COREV +#if defined(ARCHI_HAS_COREV) && (!defined(__PULP_TOOLCHAIN__) && defined(__COREV_TOOLCHAIN__)) //cv.elw t0, EU_DISPATCH_DEMUX_OFFSET + EU_DISPATCH_FIFO_ACCESS(s2) //cv.elw a0, EU_DISPATCH_DEMUX_OFFSET + EU_DISPATCH_FIFO_ACCESS(s2) lw t0, EU_DISPATCH_DEMUX_OFFSET + EU_DISPATCH_FIFO_ACCESS(s2) @@ -301,7 +301,7 @@ pos_other_entry: pos_set_slave_stack: // Multiply the stack size by the core ID and add the stack base to get our stack -#ifdef ARCHI_HAS_COREV +#if defined(ARCHI_HAS_COREV) && (!defined(__PULP_TOOLCHAIN__) && defined(__COREV_TOOLCHAIN__)) //cv.elw t0, EU_DISPATCH_DEMUX_OFFSET + EU_DISPATCH_FIFO_ACCESS(s2) lw t0, EU_DISPATCH_DEMUX_OFFSET + EU_DISPATCH_FIFO_ACCESS(s2) // beqz t0, hal_itc_wait_for_interrupt @@ -320,7 +320,7 @@ L4: // and thus we need to take the next stack addi t5, s3, 1 #endif -#ifdef ARCHI_HAS_COREV +#if defined(ARCHI_HAS_COREV) && (!defined(__PULP_TOOLCHAIN__) && defined(__COREV_TOOLCHAIN__)) cv.muls t4, t5, a0 #else p.mul t4, t5, a0 diff --git a/rtos/pulpos/pulp/rules/pulpos/targets/pulp_cv32e40p.mk b/rtos/pulpos/pulp/rules/pulpos/targets/pulp_cv32e40p.mk index 4d5da92d..ed86a564 100644 --- a/rtos/pulpos/pulp/rules/pulpos/targets/pulp_cv32e40p.mk +++ b/rtos/pulpos/pulp/rules/pulpos/targets/pulp_cv32e40p.mk @@ -1,10 +1,14 @@ CONFIG_NB_CLUSTER_PE ?= 8 -PULP_LDFLAGS += -PULP_CFLAGS += -D__riscv__ -DARCHI_HAS_COREV -DPLP_NO_BUILTIN +# Define the toolchain under use with CV32E40P. Options are `PULP_TOOLCHAIN` or `COREV_TOOLCHAIN` +TOOLCHAIN = PULP_TOOLCHAIN + +ifeq ($(TOOLCHAIN), COREV_TOOLCHAIN) +PULP_LDFLAGS += +PULP_CFLAGS += -D__riscv__ -DARCHI_HAS_COREV -D__COREV_TOOLCHAIN__ -DPLP_NO_BUILTIN PULP_ARCH_CFLAGS ?= -march=rv32imfc_xcorev PULP_ARCH_LDFLAGS ?= -march=rv32imfc_xcorev -PULP_ARCH_OBJDFLAGS ?= +PULP_ARCH_OBJDFLAGS ?= PULP_CFLAGS += -fdata-sections -ffunction-sections -include pos/chips/pulp/config.h -I$(PULPOS_PULP_HOME)/include/pos/chips/pulp PULP_OMP_CFLAGS += -fopenmp -mnativeomp PULP_LDFLAGS += -nostartfiles -nostdlib -Wl,--gc-sections -L$(PULPOS_PULP_HOME)/kernel -Tchips/pulp/link.ld -lgcc @@ -13,6 +17,24 @@ PULP_CC = riscv32-corev-elf-gcc PULP_AR ?= riscv32-corev-elf-ar PULP_LD ?= riscv32-corev-elf-gcc PULP_OBJDUMP ?= riscv32-corev-elf-objdump +else ifeq ($(TOOLCHAIN), PULP_TOOLCHAIN) +PULP_LDFLAGS += +PULP_CFLAGS += -D__riscv__ -DARCHI_HAS_COREV -DARCHI_CORE_HAS_PULPV2 -D__PULP_TOOLCHAIN__ +PULP_ARCH_CFLAGS ?= -march=rv32imcxgap9 -mPE=$(CONFIG_NB_CLUSTER_PE) -mFC=1 +PULP_ARCH_LDFLAGS ?= -march=rv32imcxgap9 -mPE=$(CONFIG_NB_CLUSTER_PE) -mFC=1 +PULP_ARCH_OBJDFLAGS ?= -Mmarch=rv32imcxgap9 +PULP_CFLAGS += -fdata-sections -ffunction-sections -include pos/chips/pulp/config.h -I$(PULPOS_PULP_HOME)/include/pos/chips/pulp -I$(PULP_EXT_LIBS)/include +ifeq '$(CONFIG_OPENMP)' '1' + PULP_CFLAGS += -fopenmp -mnativeomp +endif +PULP_OMP_CFLAGS += -fopenmp -mnativeomp +PULP_LDFLAGS += -nostartfiles -nostdlib -Wl,--gc-sections -L$(PULP_EXT_LIBS) -L$(PULPOS_PULP_HOME)/kernel -Tchips/pulp/link.ld -lgcc + +PULP_CC = riscv32-unknown-elf-gcc +PULP_AR ?= riscv32-unknown-elf-ar +PULP_LD ?= riscv32-unknown-elf-gcc +PULP_OBJDUMP ?= riscv32-unknown-elf-objdump +endif fc/archi=riscv pe/archi=riscv diff --git a/rtos/pulpos/pulp_archi/include/archi/chips/pulp/pulp.h b/rtos/pulpos/pulp_archi/include/archi/chips/pulp/pulp.h index db4d88f0..9c81df1f 100644 --- a/rtos/pulpos/pulp_archi/include/archi/chips/pulp/pulp.h +++ b/rtos/pulpos/pulp_archi/include/archi/chips/pulp/pulp.h @@ -23,11 +23,15 @@ #include "archi/gpio/gpio_v3.h" #ifdef ARCHI_HAS_COREV -#include "archi/riscv/priv_corev_1_1.h" +#include "archi/riscv/priv_corev_1_2.h" #else #include "archi/riscv/priv_1_10.h" #endif +#ifdef ARCHI_HAS_COREV +#include "archi/riscv/pcer_corev_1_1.h" +#else #include "archi/riscv/pcer_v2.h" +#endif #include "archi/itc/itc_v1.h" #include "archi/chips/pulp/memory_map.h" diff --git a/rtos/pulpos/pulp_archi/include/archi/riscv/pcer_corev_1_1.h b/rtos/pulpos/pulp_archi/include/archi/riscv/pcer_corev_1_1.h new file mode 100644 index 00000000..45f8e4a9 --- /dev/null +++ b/rtos/pulpos/pulp_archi/include/archi/riscv/pcer_corev_1_1.h @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2018 ETH Zurich and University of Bologna + * + * 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 + * + * http://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 _ARCHI_RISCV_PCER_V1_H +#define _ARCHI_RISCV_PCER_V1_H + +/* + * Bit definitions for Performance counters mode registers + * + */ +#define CSR_MHPMEVENT_CYCLES 0 /* Count the number of cycles the core was running */ +#define CSR_MHPMEVENT_INSTR 1 /* Count the number of instructions executed */ +#define CSR_MHPMEVENT_LD_STALL 2 /* Number of load use hazards */ +#define CSR_MHPMEVENT_JMP_STALL 3 /* Number of jump register hazards */ +#define CSR_MHPMEVENT_IMISS 4 /* Cycles waiting for instruction fetches. i.e. the number of instructions wasted due to non-ideal caches */ +#define CSR_MHPMEVENT_LD 5 /* Number of memory loads executed. Misaligned accesses are counted twice */ +#define CSR_MHPMEVENT_ST 6 /* Number of memory stores executed. Misaligned accesses are counted twice */ +#define CSR_MHPMEVENT_JUMP 7 /* Number of jump instructions seen, i.e. j, jr, jal, jalr */ +#define CSR_MHPMEVENT_BRANCH 8 /* Number of branch instructions seen, i.e. bf, bnf */ +#define CSR_MHPMEVENT_TAKEN_BRANCH 9 /* Number of taken branch instructions seen, i.e. bf, bnf */ +#define CSR_MHPMEVENT_RVC 10 /* Number of compressed instructions */ +#define CSR_MHPMEVENT_PIPE_STALL 11 /* Cycles from stalled pipeline */ +#define CSR_MHPMEVENT_APU_TYPE 12 /* Number of conflicts on APU/FP */ +#define CSR_MHPMEVENT_APU_CONT 13 /* Number of contentions on APU/FP */ +#define CSR_MHPMEVENT_APU_DEP 14 /* Number of dependency on APU/FP */ +#define CSR_MHPMEVENT_APU_WB 15 /* Number of write backs on APU/FP */ + + +#define CSR_MHPMEVENT_NB_EVENTS 16 +#define CSR_MHPMEVENT_NB_INTERNAL_EVENTS 12 +#define CSR_NUM_MHPMCOUNTERS 31 + +// Gives from the event ID, the HW mask that can be stored (with an OR with other events mask) to the PCER +#define CSR_PCER_EVENT_MASK(eventId) (1<<(eventId)) +#define CSR_PCER_ALL_EVENTS_MASK 0xffffffff + +#define CSR_MCOUNTINHIBIT_ACTIVE 0x0 /* Activate counting in all performance counters*/ +#define CSR_MCOUNTINHIBIT_RESET 0xfffffffd /* Inhibit/reset counting in all performance counters*/ + + +#define CSR_PCER_NAME(id) (id == 0 ? "Cycles" : id == 1 ? "Instructions" : id == 2 ? "LD_Stall" : id == 3 ? "Jmp_Stall" : id == 4 ? "IMISS" : id == 5 ? "LD" : id == 6 ? "ST" : id == 7 ? "JUMP" : id == 8 ? "BRANCH" : id == 9 ? "TAKEN_BRANCH" : id == 10 ? "RVC" : id == 11 ? "ELW" : id == 12 ? "LD_EXT" : id == 13 ? "ST_EXT" : id == 14 ? "LD_EXT_CYC" : id == 15 ? "ST_EXT_CYC" : id == 16 ? "TCDM_CONT" : "NA") + +#endif diff --git a/rtos/pulpos/pulp_archi/include/archi/riscv/priv_corev_1_2.h b/rtos/pulpos/pulp_archi/include/archi/riscv/priv_corev_1_2.h new file mode 100644 index 00000000..a68a08f6 --- /dev/null +++ b/rtos/pulpos/pulp_archi/include/archi/riscv/priv_corev_1_2.h @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2018 ETH Zurich and University of Bologna + * + * 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 + * + * http://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. + */ + +/* COREV has different addresses. Keep compatibility */ +#ifndef _ARCHI_RISCV_PRIV_1_11_H +#define _ARCHI_RISCV_PRIV_1_11_H + +#define RV_CSR_MSTATUS 0x300 +#define RV_CSR_MEPC 0x341 +#define RV_CSR_MCAUSE 0x342 +#define RV_CSR_MTVAL 0x343 + +#define RV_CSR_MISA 0x301 +#define RV_CSR_MIMPID 0xF13 +#define RV_CSR_MHARTID 0xF14 + +#define CSR_MCYCLE 0xB00 +#define CSR_MINSTRET 0xB02 +#define CSR_MHPMCOUNTER(N) (0xB03 + (N)) +#define CSR_MCOUNTINHIBIT 0x320 +#define CSR_MHPMEVENT(M) (0x323 + (M)) + +/* Not specified for COREV */ +#define CSR_STACK_CONF 0x7D0 +#define CSR_STACK_START 0x7D1 +#define CSR_STACK_END 0x7D2 + +/* Not specified for COREV */ +#define CSR_MESTATUS_INTEN_BIT 0 +#define CSR_MESTATUS_PRV_BIT 1 +#define CSR_MESTATUS_PRV_MACH 3 + +#define CSR_HWLOOP0_START 0x800 +#define CSR_HWLOOP0_END 0x801 +#define CSR_HWLOOP0_COUNTER 0x802 +#define CSR_HWLOOP1_START 0x804 +#define CSR_HWLOOP1_END 0x805 +#define CSR_HWLOOP1_COUNTER 0x806 + +#endif diff --git a/rtos/pulpos/pulp_hal/include/hal/chips/pulp/pulp.h b/rtos/pulpos/pulp_hal/include/hal/chips/pulp/pulp.h index dba6dfe7..3a843fac 100644 --- a/rtos/pulpos/pulp_hal/include/hal/chips/pulp/pulp.h +++ b/rtos/pulpos/pulp_hal/include/hal/chips/pulp/pulp.h @@ -18,7 +18,7 @@ #define __HAL_CHIPS_PULP_PULP_H__ #ifdef ARCHI_HAS_COREV -#include "hal/riscv/riscv_corev_v1.h" +#include "hal/riscv/riscv_corev_v2.h" #else #include "hal/riscv/riscv_v5.h" #endif diff --git a/rtos/pulpos/pulp_hal/include/hal/riscv/riscv_corev_v2.h b/rtos/pulpos/pulp_hal/include/hal/riscv/riscv_corev_v2.h new file mode 100644 index 00000000..59689463 --- /dev/null +++ b/rtos/pulpos/pulp_hal/include/hal/riscv/riscv_corev_v2.h @@ -0,0 +1,562 @@ +/* + * Copyright (C) 2018 ETH Zurich and University of Bologna + * + * 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 + * + * http://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 __HAL_RISCV_RISCV_V5_H__ +#define __HAL_RISCV_RISCV_V5_H__ + +#include "archi/pulp.h" + +#include "hal/riscv/types.h" +#include "archi/riscv/builtins_v2.h" +#include "archi/riscv/builtins_v2_emu.h" + +#ifndef ACHI_HAS_COREV +#define CSR_PCMR_ACTIVE 0x1 +#else +#define CSR_MCOUNTINHIBIT_ACTIVE 0x0 +#define CSR_MCOUNTINHIBIT_INHIBIT 0xfffffffd +#endif + +#define SR_MTVEC 0x305 + + +#if defined(__OPTIMIZE__) && defined(CORE_PULP_BUILTINS) && !defined(__LLVM__) + +static inline unsigned int hal_spr_read_then_clr(unsigned int reg, unsigned int val) +{ + return __builtin_pulp_read_then_spr_bit_clr(reg, val); +} + +static inline unsigned int hal_spr_read_then_set(unsigned int reg, unsigned int val) +{ + return __builtin_pulp_read_then_spr_bit_set(reg, val); +} + +static inline void hal_spr_write(unsigned int reg, unsigned int val) +{ + __builtin_pulp_spr_write(reg, val); +} + +static inline unsigned int hal_spr_read(unsigned int reg) +{ + return __builtin_pulp_spr_read(reg); +} + +#else + +#if defined(__LLVM__) + +#else + +#define hal_spr_read_then_clr(reg,val) \ + ({ \ + int state; \ + asm volatile ("csrrc %0, %1, %2" : "=r" (state) : "I" (reg), "I" (val) ); \ + state; \ + }) + +#define hal_spr_read_then_set(reg,val) \ + ({ \ + int state; \ + asm volatile ("csrrs %0, %1, %2" : "=r" (state) : "I" (reg), "I" (val) ); \ + state; \ + }) + +#define hal_spr_read_then_clr_from_reg(reg,val) \ + ({ \ + int state; \ + asm volatile ("csrrc %0, %1, %2" : "=r" (state) : "I" (reg), "r" (val) ); \ + state; \ + }) + +#define hal_spr_read_then_set(reg,val) \ + ({ \ + int state; \ + asm volatile ("csrrs %0, %1, %2" : "=r" (state) : "I" (reg), "I" (val) ); \ + state; \ + }) + +#define hal_spr_read_then_set_from_reg(reg,val) \ + ({ \ + int state; \ + asm volatile ("csrrs %0, %1, %2" : "=r" (state) : "I" (reg), "r" (val) ); \ + state; \ + }) + +#define hal_spr_write(reg,val) \ +do { \ + asm volatile ("csrw %0, %1" : : "I" (reg), "r" (val) ); \ +} while(0) + +#define hal_spr_read(reg) \ +({ \ + int result; \ + asm volatile ("csrr %0, %1" : "=r" (result) : "I" (reg) ); \ + result; \ +}) + +#endif + +#endif + + + + + +#if defined(__LLVM__) + +#define csr_read(csr) \ +({ \ + register unsigned int __v; \ + __asm__ __volatile__ ("csrr %0, " #csr \ + : "=r" (__v)); \ + __v; \ +}) + +#define hal_mepc_read() csr_read(0x341) + +#else +#define hal_mepc_read() hal_spr_read(RV_CSR_MEPC) +#endif + +static inline unsigned int core_id() { + int hart_id; +#if RISCV_VERSION >= 4 && !defined(RISCV_1_7) +#if PULP_CHIP_FAMILY == CHIP_GAP + asm("csrr %0, 0x014" : "=r" (hart_id) : ); +#else + asm("csrr %0, 0xF14" : "=r" (hart_id) : ); +#endif +#else + asm("csrr %0, 0xF10" : "=r" (hart_id) : ); +#endif + // in PULP the hart id is {22'b0, cluster_id, core_id} + return hart_id & 0x01f; +} + +static inline unsigned int cluster_id() { int hart_id; +#if RISCV_VERSION >= 4 && !defined(RISCV_1_7) +#if PULP_CHIP_FAMILY == CHIP_GAP + asm("csrr %0, 0x014" : "=r" (hart_id) : ); +#else + asm("csrr %0, 0xF14" : "=r" (hart_id) : ); +#endif +#else + asm("csrr %0, 0xF10" : "=r" (hart_id) : ); +#endif + // in PULP the hart id is {22'b0, cluster_id, core_id} + return (hart_id >> 5) & 0x3f; +} + +#ifndef PLP_NO_BUILTIN + +static inline unsigned int hal_core_id() { + return core_id(); + //return __builtin_pulp_CoreId(); +} + +static inline unsigned int hal_cluster_id() { + //return cluster_id(); + return __builtin_pulp_ClusterId(); +} + +// TODO replace by compiler builtin +static inline __attribute__((always_inline)) unsigned int hal_has_fc() { +#ifdef ARCHI_HAS_FC + return 1; +#else + return 0; +#endif +} + +static inline __attribute__((always_inline)) unsigned int hal_is_fc() { +#ifndef ARCHI_HAS_FC + return 0; +#else + if (hal_has_fc()) return hal_cluster_id() == ARCHI_FC_CID; + else return 0; +#endif +} + +#else + +static inline __attribute__((always_inline)) unsigned int hal_core_id() { + int hart_id; +#if RISCV_VERSION >= 4 && !defined(RISCV_1_7) +#if PULP_CHIP_FAMILY == CHIP_GAP + asm("csrr %0, 0x014" : "=r" (hart_id) : ); +#else + asm("csrr %0, 0xF14" : "=r" (hart_id) : ); +#endif +#else + asm("csrr %0, 0xF10" : "=r" (hart_id) : ); +#endif + // in PULP the hart id is {22'b0, cluster_id, core_id} + return hart_id & 0x01f; +} + +static inline __attribute__((always_inline)) unsigned int hal_cluster_id() { + int hart_id; +#if RISCV_VERSION >= 4 && !defined(RISCV_1_7) +#if PULP_CHIP_FAMILY == CHIP_GAP + asm("csrr %0, 0x014" : "=r" (hart_id) : ); +#else + asm("csrr %0, 0xF14" : "=r" (hart_id) : ); +#endif +#else + asm("csrr %0, 0xF10" : "=r" (hart_id) : ); +#endif + // in PULP the hart id is {22'b0, cluster_id, core_id} + return (hart_id >> 5) & 0x3f; +} + +static inline __attribute__((always_inline)) unsigned int hal_has_fc() { +#ifdef ARCHI_HAS_FC + return 1; +#else + return 0; +#endif +} + +static inline __attribute__((always_inline)) unsigned int hal_is_fc() { +#ifndef ARCHI_HAS_FC + return 0; +#else + if (hal_has_fc()) return hal_cluster_id() == ARCHI_FC_CID; + else return 0; +#endif +} + +#endif + + + +#if defined(__LLVM__) + +static inline int hal_irq_disable() +{ + return 0; +} + +static inline void hal_irq_restore(int state) +{ +} + +static inline void hal_irq_enable() +{ +} + +#else + +static inline int hal_irq_disable() +{ + int irq = hal_spr_read_then_clr(0x300, 0x1<<3); + // This memory barrier is needed to prevent the compiler to cross the irq barrier + __asm__ __volatile__ ("" : : : "memory"); + return irq; +} + +static inline void hal_irq_restore(int state) +{ + // This memory barrier is needed to prevent the compiler to cross the irq barrier + __asm__ __volatile__ ("" : : : "memory"); + hal_spr_write(0x300, state); +} + +static inline void hal_irq_enable() +{ + // This memory barrier is needed to prevent the compiler to cross the irq barrier + __asm__ __volatile__ ("" : : : "memory"); + hal_spr_read_then_set(0x300, 0x1<<3); +} + +#endif + +/* + * PERFORMANCE COUNTERS + * + * API for accessing performance counters registers. + * Have a look at file spr-defs.h to speficy registers through defines + * SPR_PCER_* and SPR_PCMR_* + */ + +#ifndef ARCHI_HAS_COREV +#define PCER_NB_EVENTS CSR_PCER_NB_EVENTS +#define PCER_ALL_EVENTS_MASK CSR_PCER_ALL_EVENTS_MASK +#define PCMR_ACTIVE CSR_PCMR_ACTIVE +#define PCMR_SATURATE CSR_PCMR_SATURATE +#else +#define MCOUNTINHIBIT_ACTIVE CSR_MCOUNTINHIBIT_ACTIVE +#define MCOUNTINHIBIT_RESET CSR_MCOUNTINHIBIT_RESET +#endif + +#define CSR_CONVERT(x) #x +#define CSR_WRITE(x, var) asm volatile ("csrw "CSR_CONVERT(x)", %0" :: "r" (var)) +#define CSR_READ(x, var) asm volatile ("csrr %0, "CSR_CONVERT(x)"" : "=r" (var) :) + +/* Configure the active events. eventMask is an OR of events got through SPR_PCER_EVENT_MASK */ +static inline void cpu_perf_conf_events(unsigned int eventMask) +{ +#ifndef PLP_NO_PERF_COUNTERS + #ifndef ARCHI_HAS_COREV + CSR_WRITE(CSR_PCER, eventMask); + #else + + /* mhpmcounter3 is used for sharing events when only one counter is implemented */ + CSR_WRITE(CSR_MHPMEVENT(0), eventMask); + + /* Associate events to counters 1:1 using the Event Selector*/ + CSR_WRITE(CSR_MHPMEVENT(1), (1 << 0) & eventMask); + CSR_WRITE(CSR_MHPMEVENT(2), (1 << 1) & eventMask); + CSR_WRITE(CSR_MHPMEVENT(3), (1 << 2) & eventMask); + CSR_WRITE(CSR_MHPMEVENT(4), (1 << 3) & eventMask); + CSR_WRITE(CSR_MHPMEVENT(5), (1 << 4) & eventMask); + CSR_WRITE(CSR_MHPMEVENT(6), (1 << 5) & eventMask); + CSR_WRITE(CSR_MHPMEVENT(7), (1 << 6) & eventMask); + CSR_WRITE(CSR_MHPMEVENT(8), (1 << 7) & eventMask); + CSR_WRITE(CSR_MHPMEVENT(9), (1 << 8) & eventMask); + CSR_WRITE(CSR_MHPMEVENT(10), (1 << 9) & eventMask); + CSR_WRITE(CSR_MHPMEVENT(11), (1 << 10) & eventMask); + CSR_WRITE(CSR_MHPMEVENT(12), (1 << 11) & eventMask); + CSR_WRITE(CSR_MHPMEVENT(13), (1 << 12) & eventMask); + CSR_WRITE(CSR_MHPMEVENT(14), (1 << 13) & eventMask); + CSR_WRITE(CSR_MHPMEVENT(15), (1 << 14) & eventMask); + CSR_WRITE(CSR_MHPMEVENT(16), (1 << 15) & eventMask); + #endif +#endif +} + +/* Return events configuration */ +static inline unsigned int cpu_perf_conf_events_get() +{ +#ifndef PLP_NO_PERF_COUNTERS + unsigned int result; + CSR_READ(CSR_PCER, result); + return result; +#else + return 0; +#endif +} + +/* Configure the mode. confMask is an OR of all SPR_PCMR_* macros */ +static inline void cpu_perf_conf(unsigned int confMask) +{ +#ifndef PLP_NO_PERF_COUNTERS + #ifndef ARCHI_HAS_COREV + CSR_WRITE(CSR_PCMR, confMask); + #else + CSR_WRITE(CSR_MCOUNTINHIBIT, confMask); // Enable all the counters + #endif +#endif +} + +/* Starts counting in all counters. As this is using the mode register, + * the rest of the config can be given through conf parameter */ +static inline void cpu_perf_start(unsigned int conf) { +#ifndef PLP_NO_PERF_COUNTERS + #ifndef ARCHI_HAS_COREV + cpu_perf_conf(conf | CSR_PCMR_ACTIVE); // TODO + #else + cpu_perf_conf(conf); + #endif +#endif +} + +/* Stops counting in all counters. As this is using the mode register, + * the rest of the config can be given through conf parameter */ +static inline void cpu_perf_stop(unsigned int conf) { +#ifndef PLP_NO_PERF_COUNTERS + cpu_perf_conf(conf); // TODO +#endif +} + +/* Set the specified counter to the specified value */ +static inline void cpu_perf_set(unsigned int counterId, unsigned int value) { + +} + +/* Set all counters to the specified value */ +static inline void cpu_perf_setall(unsigned int value) { +#ifndef PLP_NO_PERF_COUNTERS + #ifndef ARCHI_HAS_COREV + asm volatile ("csrw 0x79F, %0" :: "r" (value)); + #else + CSR_WRITE(CSR_MCOUNTINHIBIT, value); + #endif +#endif +} + +#ifndef PLP_NO_PERF_COUNTERS + #ifdef ARCHI_HAS_COREV + static inline unsigned int cpu_perf_get_mcycle() { + unsigned int value=0; + CSR_READ(CSR_MCYCLE, value); + + return value; + } + static inline unsigned int cpu_perf_get_minstret() { + unsigned int value=0; + CSR_READ(CSR_MINSTRET, value); + + return value; + } + #endif +#endif + +/* Return the value of the specified counter */ +static inline unsigned int cpu_perf_get(const unsigned int counterId) { +#ifndef PLP_NO_PERF_COUNTERS + unsigned int value = 0; + + #ifndef ARCHI_HAS_COREV + switch(counterId) { + case 0: CSR_READ(CSR_PCCR(0), value); break; + case 1: CSR_READ(CSR_PCCR(1), value); break; + case 2: CSR_READ(CSR_PCCR(2), value); break; + case 3: CSR_READ(CSR_PCCR(3), value); break; + case 4: CSR_READ(CSR_PCCR(4), value); break; + case 5: CSR_READ(CSR_PCCR(5), value); break; + case 6: CSR_READ(CSR_PCCR(6), value); break; + case 7: CSR_READ(CSR_PCCR(7), value); break; + case 8: CSR_READ(CSR_PCCR(8), value); break; + case 9: CSR_READ(CSR_PCCR(9), value); break; + case 10: CSR_READ(CSR_PCCR(10), value); break; + case 11: CSR_READ(CSR_PCCR(11), value); break; + case 12: CSR_READ(CSR_PCCR(12), value); break; + case 13: CSR_READ(CSR_PCCR(13), value); break; + case 14: CSR_READ(CSR_PCCR(14), value); break; + case 15: CSR_READ(CSR_PCCR(15), value); break; + case 16: CSR_READ(CSR_PCCR(16), value); break; + case 17: CSR_READ(CSR_PCCR(17), value); break; + case 18: CSR_READ(CSR_PCCR(18), value); break; + case 19: CSR_READ(CSR_PCCR(19), value); break; + case 20: CSR_READ(CSR_PCCR(20), value); break; + case 21: CSR_READ(CSR_PCCR(21), value); break; + case 22: CSR_READ(CSR_PCCR(22), value); break; + case 23: CSR_READ(CSR_PCCR(23), value); break; + case 24: CSR_READ(CSR_PCCR(24), value); break; + case 25: CSR_READ(CSR_PCCR(25), value); break; + case 26: CSR_READ(CSR_PCCR(26), value); break; + case 27: CSR_READ(CSR_PCCR(27), value); break; + case 28: CSR_READ(CSR_PCCR(28), value); break; + case 29: CSR_READ(CSR_PCCR(29), value); break; + case 30: CSR_READ(CSR_PCCR(30), value); break; + } + + #else + + // Read from performance counters + switch(counterId) { + case 0: CSR_READ(CSR_MHPMCOUNTER(0), value); break; // mhpmcounterh3 + case 1: CSR_READ(CSR_MHPMCOUNTER(1), value); break; + case 2: CSR_READ(CSR_MHPMCOUNTER(2), value); break; + case 3: CSR_READ(CSR_MHPMCOUNTER(3), value); break; + case 4: CSR_READ(CSR_MHPMCOUNTER(4), value); break; + case 5: CSR_READ(CSR_MHPMCOUNTER(5), value); break; + case 6: CSR_READ(CSR_MHPMCOUNTER(6), value); break; + case 7: CSR_READ(CSR_MHPMCOUNTER(7), value); break; + case 8: CSR_READ(CSR_MHPMCOUNTER(8), value); break; + case 9: CSR_READ(CSR_MHPMCOUNTER(9), value); break; + case 10: CSR_READ(CSR_MHPMCOUNTER(10), value); break; + case 11: CSR_READ(CSR_MHPMCOUNTER(11), value); break; + case 12: CSR_READ(CSR_MHPMCOUNTER(12), value); break; + case 13: CSR_READ(CSR_MHPMCOUNTER(13), value); break; + case 14: CSR_READ(CSR_MHPMCOUNTER(14), value); break; + case 15: CSR_READ(CSR_MHPMCOUNTER(15), value); break; + case 16: CSR_READ(CSR_MHPMCOUNTER(16), value); break; + case 17: CSR_READ(CSR_MHPMCOUNTER(17), value); break; + case 18: CSR_READ(CSR_MHPMCOUNTER(18), value); break; + case 19: CSR_READ(CSR_MHPMCOUNTER(19), value); break; + case 20: CSR_READ(CSR_MHPMCOUNTER(20), value); break; + case 21: CSR_READ(CSR_MHPMCOUNTER(21), value); break; + case 22: CSR_READ(CSR_MHPMCOUNTER(22), value); break; + case 23: CSR_READ(CSR_MHPMCOUNTER(23), value); break; + case 24: CSR_READ(CSR_MHPMCOUNTER(24), value); break; + case 25: CSR_READ(CSR_MHPMCOUNTER(25), value); break; + case 26: CSR_READ(CSR_MHPMCOUNTER(26), value); break; + case 27: CSR_READ(CSR_MHPMCOUNTER(27), value); break; + case 28: CSR_READ(CSR_MHPMCOUNTER(28), value); break; // mhpmcounterh31 + } + #endif + return value; +#else + return 0; +#endif +} + +static inline const char *cpu_perf_name(int event) { + #ifndef ARCHI_HAS_COREV + switch (event) { + case 0: return "CYCLES"; + case 1: return "INSTR"; + case 2: return "LD_STALL"; + case 3: return "JMP_STALL"; + case 4: return "IMISS"; + case 5: return "LD"; + case 6: return "ST"; + case 7: return "JUMP"; + case 8: return "BRANCH"; + case 9: return "TAKEN_BRANCH"; + case 10: return "RVC"; + case 11: return "LD_EXT"; + case 12: return "ST_EXT"; + case 13: return "LD_EXT_CYC"; + case 14: return "ST_EXT_CYC"; + case 15: return "TCDM_CONT"; + } + #else + switch (event) { + case 0: return "CYCLES"; + case 1: return "INSTR"; + case 2: return "LD_STALL"; + case 3: return "JMP_STALL"; + case 4: return "IMISS"; + case 5: return "LD"; + case 6: return "ST"; + case 7: return "JUMP"; + case 8: return "BRANCH"; + case 9: return "TAKEN_BRANCH"; + case 10: return "RVC"; + case 11: return "PIPE_STALL"; + case 12: return "APU_TYPE"; + case 13: return "APU_CONT"; + case 14: return "APU_DEP"; + case 15: return "APU_WB"; + } + #endif + return (char *)0; +} + + + +/* + * Stack checking + */ + +static inline void cpu_stack_check_enable(unsigned int base, unsigned int end) +{ + asm volatile ("csrwi 0x7D0, 0" :: ); + asm volatile ("csrw 0x7D1, %0" :: "r" (base)); + asm volatile ("csrw 0x7D2, %0" :: "r" (end)); + asm volatile ("csrwi 0x7D0, 1" :: ); +} + +static inline void cpu_stack_check_disable() +{ + asm volatile ("csrwi 0x7D0, 0" :: ); +} + +#endif