pulp-runtime/include/hal/ibex/ibex.h

297 lines
10 KiB
C

/*
* Copyright (C) 2020 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_IBEX_IBEX_H__
#define __HAL_IBEX_IBEX_H__
#include "archi/pulp.h"
#include "archi/riscv/builtins_v2_emu.h"
// For PULP, ibex added non-standard irqs to allow for 32 fast interrupts.
// These use custom CSRs: MIE: 0x7D0, MTVEC: 0x7D1, MIP: 0x7D2
#define SR_MTVEC 0x7D1
#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; \
})
#define hal_mepc_read() hal_spr_read(RV_CSR_MEPC)
static inline unsigned int core_id() {
int hart_id;
asm("csrr %0, 0xF14" : "=r" (hart_id) : );
// 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;
asm("csrr %0, 0xF14" : "=r" (hart_id) : );
// in PULP the hart id is {22'b0, cluster_id, core_id}
#if PULP_CHIP == CHIP_CARFIELD
return (hart_id >> 6);
#else
return (hart_id >> 5) & 0x3f;
#endif
}
static inline unsigned int hal_core_id() {
return core_id();
}
static inline unsigned int hal_cluster_id() {
return cluster_id();
}
// 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
}
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);
}
/*
* PERFORMANCE COUNTERS
*
* API for accessing performance counters registers.
* Have a look at file mhpm.h to speficy registers through defines
* CSR_PCER_* and CSR_PCMR_*
*/
#define PCER_NB_EVENTS CSR_PCER_NB_EVENTS
#define PCER_ALL_EVENTS_MASK CSR_PCER_ALL_EVENTS_MASK
/* 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
unsigned int test = ~eventMask;
asm volatile ("csrw 0x320, %0" : "+r" (test));
#endif
}
/* Return events configuration */
static inline unsigned int cpu_perf_conf_events_get()
{
#ifndef PLP_NO_PERF_COUNTERS
unsigned int result;
asm volatile ("csrr %0, 0x320" : "=r" (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
asm volatile ("csrw 0x320, %0" :: "r" (~confMask));
#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() {
#ifndef PLP_NO_PERF_COUNTERS
cpu_perf_conf(CSR_PCER_ALL_EVENTS_MASK);
#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() {
#ifndef PLP_NO_PERF_COUNTERS
cpu_perf_conf(0);
#endif
}
/* Set the specified counter to the specified value */
static inline void cpu_perf_set(unsigned int counterId, unsigned int value) {
switch(counterId) {
case 0: asm volatile ("csrw 0xB00, %0" : : "r" (value) ); break;
case 1: break; // This CSR does not exist
case 2: asm volatile ("csrw 0xB02, %0" : : "r" (value) ); break;
case 3: asm volatile ("csrw 0xB03, %0" : : "r" (value) ); break;
case 4: asm volatile ("csrw 0xB04, %0" : : "r" (value) ); break;
case 5: asm volatile ("csrw 0xB05, %0" : : "r" (value) ); break;
case 6: asm volatile ("csrw 0xB06, %0" : : "r" (value) ); break;
case 7: asm volatile ("csrw 0xB07, %0" : : "r" (value) ); break;
case 8: asm volatile ("csrw 0xB08, %0" : : "r" (value) ); break;
case 9: asm volatile ("csrw 0xB09, %0" : : "r" (value) ); break;
case 10: asm volatile ("csrw 0xB0A, %0" : : "r" (value) ); break;
case 11: asm volatile ("csrw 0xB0B, %0" : : "r" (value) ); break;
case 12: asm volatile ("csrw 0xB0C, %0" : : "r" (value) ); break;
case 13: asm volatile ("csrw 0xB0D, %0" : : "r" (value) ); break;
case 14: asm volatile ("csrw 0xB0E, %0" : : "r" (value) ); break;
case 15: asm volatile ("csrw 0xB0F, %0" : : "r" (value) ); break;
case 16: asm volatile ("csrw 0xB10, %0" : : "r" (value) ); break;
case 17: asm volatile ("csrw 0xB11, %0" : : "r" (value) ); break;
case 18: asm volatile ("csrw 0xB12, %0" : : "r" (value) ); break;
case 19: asm volatile ("csrw 0xB13, %0" : : "r" (value) ); break;
case 20: asm volatile ("csrw 0xB14, %0" : : "r" (value) ); break;
case 21: asm volatile ("csrw 0xB15, %0" : : "r" (value) ); break;
case 22: asm volatile ("csrw 0xB16, %0" : : "r" (value) ); break;
case 23: asm volatile ("csrw 0xB17, %0" : : "r" (value) ); break;
case 24: asm volatile ("csrw 0xB18, %0" : : "r" (value) ); break;
case 25: asm volatile ("csrw 0xB19, %0" : : "r" (value) ); break;
case 26: asm volatile ("csrw 0xB1A, %0" : : "r" (value) ); break;
case 27: asm volatile ("csrw 0xB1B, %0" : : "r" (value) ); break;
case 28: asm volatile ("csrw 0xB1C, %0" : : "r" (value) ); break;
case 29: asm volatile ("csrw 0xB1D, %0" : : "r" (value) ); break;
case 30: asm volatile ("csrw 0xB1E, %0" : : "r" (value) ); break;
case 31: asm volatile ("csrw 0xB1F, %0" : : "r" (value) ); break;
}
}
/* Set all counters to the specified value */
static inline void cpu_perf_setall(unsigned int value) {
#ifndef PLP_NO_PERF_COUNTERS
// This implementation is rather slow. ri5cy has a register to set all, ibex does not.
for (int i = 0; i < CSR_PCER_TOP_EVENT; i++) {
cpu_perf_set(i, value);
}
#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;
switch(counterId) {
case 0: asm volatile ("csrr %0, 0xB00" : "=r" (value)); break;
case 1: break; // This CSR does not exist
case 2: asm volatile ("csrr %0, 0xB02" : "=r" (value)); break;
case 3: asm volatile ("csrr %0, 0xB03" : "=r" (value)); break;
case 4: asm volatile ("csrr %0, 0xB04" : "=r" (value)); break;
case 5: asm volatile ("csrr %0, 0xB05" : "=r" (value)); break;
case 6: asm volatile ("csrr %0, 0xB06" : "=r" (value)); break;
case 7: asm volatile ("csrr %0, 0xB07" : "=r" (value)); break;
case 8: asm volatile ("csrr %0, 0xB08" : "=r" (value)); break;
case 9: asm volatile ("csrr %0, 0xB09" : "=r" (value)); break;
case 10: asm volatile ("csrr %0, 0xB0A" : "=r" (value)); break;
case 11: asm volatile ("csrr %0, 0xB0B" : "=r" (value)); break;
case 12: asm volatile ("csrr %0, 0xB0C" : "=r" (value)); break;
case 13: asm volatile ("csrr %0, 0xB0D" : "=r" (value)); break;
case 14: asm volatile ("csrr %0, 0xB0E" : "=r" (value)); break;
case 15: asm volatile ("csrr %0, 0xB0F" : "=r" (value)); break;
case 16: asm volatile ("csrr %0, 0xB10" : "=r" (value)); break;
case 17: asm volatile ("csrr %0, 0xB11" : "=r" (value)); break;
case 18: asm volatile ("csrr %0, 0xB12" : "=r" (value)); break;
case 19: asm volatile ("csrr %0, 0xB13" : "=r" (value)); break;
case 20: asm volatile ("csrr %0, 0xB14" : "=r" (value)); break;
case 21: asm volatile ("csrr %0, 0xB15" : "=r" (value)); break;
case 22: asm volatile ("csrr %0, 0xB16" : "=r" (value)); break;
case 23: asm volatile ("csrr %0, 0xB17" : "=r" (value)); break;
case 24: asm volatile ("csrr %0, 0xB18" : "=r" (value)); break;
case 25: asm volatile ("csrr %0, 0xB19" : "=r" (value)); break;
case 26: asm volatile ("csrr %0, 0xB1A" : "=r" (value)); break;
case 27: asm volatile ("csrr %0, 0xB1B" : "=r" (value)); break;
case 28: asm volatile ("csrr %0, 0xB1C" : "=r" (value)); break;
case 29: asm volatile ("csrr %0, 0xB1D" : "=r" (value)); break;
case 30: asm volatile ("csrr %0, 0xB1E" : "=r" (value)); break;
case 31: asm volatile ("csrr %0, 0xB1F" : "=r" (value)); break;
}
return value;
#else
return 0;
#endif
}
static inline const char *cpu_perf_name(int event) {
return CSR_PCER_NAME(event);
}
#endif