Skip to content

Commit

Permalink
risc-v: make CSR access more generic
Browse files Browse the repository at this point in the history
Signed-off-by: Axel Heider <axelheider@gmx.de>
  • Loading branch information
axel-h committed Nov 8, 2023
1 parent b6f1548 commit 0ac3031
Show file tree
Hide file tree
Showing 3 changed files with 115 additions and 43 deletions.
80 changes: 45 additions & 35 deletions include/arch/riscv/arch/32/mode/machine.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

#include <util.h>
#include <arch/model/smp.h>
#include <arch/machine/registerset.h>
#include <stdint.h>
#include <plat/machine/devices_gen.h>

Expand All @@ -18,50 +19,59 @@
*/
#define CLINT_MTIME_OFFSET_LO 0xbff8
#define CLINT_MTIME_OFFSET_HI 0xbffc
#endif

static inline uint64_t riscv_read_time(void)
static inline uint32_t riscv_read_clint_u32(word_t offset)
{
word_t nH1, nL, nH2;
return *(volatile uint32_t *)(CLINT_PPTR + offset);
}

#ifdef CONFIG_RISCV_USE_CLINT_MTIME
nH1 = *(volatile uint32_t *)(CLINT_PPTR + CLINT_MTIME_OFFSET_HI);
nL = *(volatile uint32_t *)(CLINT_PPTR + CLINT_MTIME_OFFSET_LO);
nH2 = *(volatile uint32_t *)(CLINT_PPTR + CLINT_MTIME_OFFSET_HI);
if (nH1 != nH2) {
/* Ensure that the time is correct if there is a rollover in the
* high bits between reading the low and high bits. */
nL = *(volatile uint32_t *)(CLINT_PPTR + CLINT_MTIME_OFFSET_LO);
static inline uint64_t riscv_read_clint_mtime(void)
{
/*
* Ensure that the time is correct if there is a rollover in the
* high bits between reading the low and high bits.
*/
uint32_t nH_prev = riscv_read_clint_u32(CLINT_MTIME_OFFSET_HI);
uint32_t nL = riscv_read_clint_u32(CLINT_MTIME_OFFSET_LO);
uint32_t nH = riscv_read_clint_u32(CLINT_MTIME_OFFSET_HI);
if (nH_prev != nH) {
nL = riscv_read_clint_u32(CLINT_MTIME_OFFSET_LO);
}
return (((uint64_t)nH) << 32) | nL;
}

#endif /* CONFIG_RISCV_USE_CLINT_MTIME */

/* create get_riscv_csr_timeh() */
declare_helper_get_riscv_csr(timeh, RISCV_CSR_TIMEH)
/* create get_riscv_counter_csr64_time() */
declare_helper_get_riscv_counter_csr64(time, RISCV_CSR_TIMEH,
RISCV_CSR_TIME)

/* create get_riscv_csr_cycleh() */
declare_helper_get_riscv_csr(cycleh, RISCV_CSR_CYCLEH)
/* create get_riscv_counter_csr64_cycle() */
declare_helper_get_riscv_counter_csr64(cycle, RISCV_CSR_CYCLEH,
RISCV_CSR_CYCLE)

/* create get_riscv_csr_instreth() */
declare_helper_get_riscv_csr(cycleh, RISCV_CSR_INSTRETH)
/* create get_riscv_counter_csr64_instret() */
declare_helper_get_riscv_counter_csr64(instret, RISCV_CSR_INSTRETH,
RISCV_CSR_INSTRET)


static inline uint64_t riscv_read_time(void)
{
#ifdef CONFIG_RISCV_USE_CLINT_MTIME
return riscv_read_clint_mtime();
#else
asm volatile(
"rdtimeh %0\n"
"rdtime %1\n"
"rdtimeh %2\n"
: "=r"(nH1), "=r"(nL), "=r"(nH2));
if (nH1 != nH2) {
/* Ensure that the time is correct if there is a rollover in the
* high bits between reading the low and high bits. */
asm volatile("rdtime %0\n" : "=r"(nL));
}
return get_riscv_counter_csr64_time();
#endif

return (((uint64_t)nH2) << 32) | nL;
}


static inline uint64_t riscv_read_cycle(void)
{
word_t nH1, nL, nH2;
asm volatile(
"rdcycleh %0\n"
"rdcycle %1\n"
"rdcycleh %2\n"
: "=r"(nH1), "=r"(nL), "=r"(nH2));
if (nH1 != nH2) {
/* Ensure that the cycles are correct if there is a rollover in the
* high bits between reading the low and high bits. */
asm volatile("rdcycle %0\n" : "=r"(nL));
}
return (((uint64_t)nH2) << 32) | nL;
return get_riscv_counter_csr64_cycle();
}
24 changes: 16 additions & 8 deletions include/arch/riscv/arch/64/mode/machine.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

#include <util.h>
#include <arch/model/smp.h>
#include <arch/machine/registerset.h>
#include <stdint.h>
#include <plat/machine/devices_gen.h>

Expand All @@ -17,22 +18,29 @@
* mapped at the same offset of the base address of the CLINT.
*/
#define CLINT_MTIME_OFFSET 0xbff8
#endif

static inline uint64_t riscv_read_clint_u64(word_t offset)
{
return *(volatile uint64_t *)(CLINT_PPTR + offset);
}

static inline uint64_t riscv_read_clint_mtime(void)
{
return riscv_read_clint_u64(CLINT_MTIME_OFFSET);
}

#endif /* CONFIG_RISCV_USE_CLINT_MTIME */

static inline uint64_t riscv_read_time(void)
{
word_t n;
#ifdef CONFIG_RISCV_USE_CLINT_MTIME
n = *(volatile word_t *)(CLINT_PPTR + CLINT_MTIME_OFFSET);
return riscv_read_clint_mtime();
#else
asm volatile("rdtime %0" : "=r"(n));
return get_riscv_csr_time();
#endif
return n;
}

static inline uint64_t riscv_read_cycle(void)
{
word_t n;
asm volatile("rdcycle %0" : "=r"(n));
return n;
return get_riscv_csr_cycle();
}
54 changes: 54 additions & 0 deletions include/arch/riscv/arch/machine/registerset.h
Original file line number Diff line number Diff line change
Expand Up @@ -184,4 +184,58 @@ static inline word_t CONST sanitiseRegister(register_t reg, word_t v, bool_t arc
[seL4_TimeoutReply_TP] = TP, \
}

#define RISCV_CSR_CYCLE 0xc00
#define RISCV_CSR_TIME 0xc01
#define RISCV_CSR_INSTRET 0xc02
#ifdef CONFIG_ARCH_RISCV32
#define RISCV_CSR_CYCLEH 0xc80
#define RISCV_CSR_TIMEH 0xc81
#define RISCV_CSR_INSTRETH 0xc82
#endif /* CONFIG_ARCH_RISCV32 */


#define RISCV_CSR_READ(_id_, _var_) \
asm volatile("csrr %0, " #_id_ : "=r" (_var_) : : "memory")

#define declare_helper_get_riscv_csr(_name_, _id_) \
static inline word_t get_riscv_csr_##_name_(void) \
{ \
register word_t val; \
RISCV_CSR_READ(_id_, val); \
return val; \
}

#ifdef CONFIG_ARCH_RISCV32

/* Read a consistent 64-bit counter value from two 32-bit registers. The value
* from the low register is used only if there was no roll over, otherwise it is
* simply taken as 0. This is an acceptable optimization if the value must have
* been 0 at some point anyway and certain jitter is acceptable. For high
* frequency counters the preference usually not on getting an exact value, but
* a value close to the point in time where the read function was called. For a
* low frequency counter, the low value is likely 0 anyway when a roll over
* happens.
*/
#define declare_helper_get_riscv_counter_csr64(_name_, _id_hi_, _id_lo_) \
static inline uint64_t get_riscv_counter_csr64_##_name_(void) \
{ \
register word_t nH_prev, nH, nL; \
RISCV_CSR_READ(_id_hi_, nH_prev); \
RISCV_CSR_READ(_id_lo_, nL); \
RISCV_CSR_READ(_id_hi_, nH); \
if (nH_prev != nH) { RISCV_CSR_READ(_id_lo_, nL); } \
return (((uint64_t)nH) << 32) | nL; \
}

#endif /* CONFIG_ARCH_RISCV32 */

/* create get_riscv_csr_cycle() */
declare_helper_get_riscv_csr(cycle, RISCV_CSR_CYCLE)

/* create get_riscv_csr_time() */
declare_helper_get_riscv_csr(time, RISCV_CSR_TIME)

/* create get_riscv_csr_instret() */
declare_helper_get_riscv_csr(instret, RISCV_CSR_INSTRET)

#endif /* __ASSEMBLER__ */

0 comments on commit 0ac3031

Please sign in to comment.