blob: fbef7c19b0e8127c53c5a91074102d6df7c28873 [file] [log] [blame]
/*
* Copyright 2017, Data61, CSIRO (ABN 41 687 119 230)
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#pragma once
#include <stdint.h>
#include <sel4bench/cpu/events.h>
//function attributes
//functions that need to be forced inline
#define FASTFN inline __attribute__((always_inline))
//functions that must not cache miss
#define CACHESENSFN __attribute__((noinline, aligned(32)))
//functions that will be called through pointers, but need to be fast
#define KERNELFN __attribute__((noinline, flatten))
//counters and related constants
#define SEL4BENCH_ARM1136_NUM_COUNTERS 2
#define SEL4BENCH_ARM1136_COUNTER_CCNT "1"
#define SEL4BENCH_ARM1136_COUNTER_PMN0 "2"
#define SEL4BENCH_ARM1136_COUNTER_PMN1 "3"
/*
* PMNC: ARM1136 Performance Monitor Control Register
*
* bits 31:28 = SBZ
* bits 27:20 = EvtCount1 = event monitored by counter 1
* bits 19:12 = EvtCount2 = event monitored by counter 2
* bit 11 = X = export events to ETM
* bits 10: 8 = Flag = read: determines if C0 (bit 8)/
* C1 (bit 9)/CCNT (bit 10)
* overflowed
* write: clears overflow flag
* bit 7 = SBZ
* bits 6: 4 = IntEn = Enable interrupt reporting for
* C0 (bit 4)/C1 (bit 5)/CCNT (bit 6)
* bit 3 = D = cycle counter divides by 64
* bit 2 = C = write 1 to reset CCNT to zero
* bit 1 = P = write 1 to reset C0 and C1 to zero
* bit 0 = E = enable all three counters
*/
typedef union {
struct {
uint32_t E : 1;
uint32_t P : 1;
uint32_t C : 1;
uint32_t D : 1;
uint32_t IntEn : 3;
uint32_t SBZ1 : 1;
uint32_t Flag : 3;
uint32_t X : 1;
uint32_t EvtCount2 : 8;
uint32_t EvtCount1 : 8;
uint32_t SBZ2 : 4;
};
uint32_t raw;
} sel4bench_arm1136_pmnc_t;
static CACHESENSFN void sel4bench_private_set_pmnc(sel4bench_arm1136_pmnc_t val)
{
/*
* The ARM1136 has a 3-cycle delay between changing the PMNC and the
* counters reacting. So we insert 3 nops to cover for that. Aligning on a
* cache line boundary guarantees that the nops won't cause anything
* interesting to happen.
*/
asm volatile (
"mcr p15, 0, %0, c15, c12, 0;"
"nop;"
"nop;"
"nop;"
:
: "r"(val.raw)
);
}
static FASTFN sel4bench_arm1136_pmnc_t sel4bench_private_get_pmnc(void)
{
sel4bench_arm1136_pmnc_t val;
asm volatile (
"mrc p15, 0, %0, c15, c12, 0"
: "=r"(val.raw)
:
);
return val;
}
/*
* CCNT: cycle counter
*/
static FASTFN uint32_t sel4bench_private_get_ccnt()
{
uint32_t val;
asm volatile (
"mrc p15, 0, %0, c15, c12," SEL4BENCH_ARM1136_COUNTER_CCNT
: "=r"(val)
);
return val;
}
/*
* PMN0: event count 0
*/
static FASTFN uint32_t sel4bench_private_get_pmn0()
{
uint32_t val;
asm volatile (
"mrc p15, 0, %0, c15, c12,"SEL4BENCH_ARM1136_COUNTER_PMN0
: "=r"(val)
);
return val;
}
static FASTFN void sel4bench_private_set_pmn0(uint32_t val)
{
asm volatile (
"mcr p15, 0, %0, c15, c12,"SEL4BENCH_ARM1136_COUNTER_PMN0
: "=r"(val)
);
}
/*
* PMN1: event count 1
*/
static FASTFN uint32_t sel4bench_private_get_pmn1()
{
uint32_t val;
asm volatile (
"mrc p15, 0, %0, c15, c12,"SEL4BENCH_ARM1136_COUNTER_PMN1
: "=r"(val)
);
return val;
}
static FASTFN void sel4bench_private_set_pmn1(uint32_t val)
{
asm volatile (
"mcr p15, 0, %0, c15, c12,"SEL4BENCH_ARM1136_COUNTER_PMN1
: "=r"(val)
);
}