mirror of
https://github.com/saymrwulf/pulp-runtime.git
synced 2026-05-14 20:48:09 +00:00
297 lines
10 KiB
C
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
|