1/*
2 * Copyright 2017, Data61
3 * Commonwealth Scientific and Industrial Research Organisation (CSIRO)
4 * ABN 41 687 119 230.
5 *
6 * This software may be distributed and modified according to the terms of
7 * the BSD 2-Clause license. Note that NO WARRANTY is provided.
8 * See "LICENSE_BSD2.txt" for details.
9 *
10 * @TAG(DATA61_BSD)
11 */
12#pragma once
13
14#include <stdint.h>
15#include <sel4bench/cpu/events.h>
16
17//function attributes
18//functions that need to be forced inline
19#define FASTFN inline __attribute__((always_inline))
20
21//functions that must not cache miss
22#define CACHESENSFN __attribute__((noinline, aligned(32)))
23
24//functions that will be called through pointers, but need to be fast
25#define KERNELFN __attribute__((noinline, flatten))
26
27//counters and related constants
28#define SEL4BENCH_ARM1136_NUM_COUNTERS 2
29
30#define SEL4BENCH_ARM1136_COUNTER_CCNT "1"
31#define SEL4BENCH_ARM1136_COUNTER_PMN0 "2"
32#define SEL4BENCH_ARM1136_COUNTER_PMN1 "3"
33
34/*
35 * PMNC: ARM1136 Performance Monitor Control Register
36 *
37 *  bits 31:28 = SBZ
38 *  bits 27:20 = EvtCount1 = event monitored by counter 1
39 *  bits 19:12 = EvtCount2 = event monitored by counter 2
40 *  bit     11 = X         = export events to ETM
41 *  bits 10: 8 = Flag      = read: determines if C0 (bit 8)/
42 *                                 C1 (bit 9)/CCNT (bit 10)
43 *                                 overflowed
44 *                           write: clears overflow flag
45 *  bit      7 = SBZ
46 *  bits  6: 4 = IntEn     = Enable interrupt reporting for
47 *                           C0 (bit 4)/C1 (bit 5)/CCNT (bit 6)
48 *  bit      3 = D         = cycle counter divides by 64
49 *  bit      2 = C         = write 1 to reset CCNT to zero
50 *  bit      1 = P         = write 1 to reset C0 and C1 to zero
51 *  bit      0 = E         = enable all three counters
52 */
53typedef union {
54    struct {
55        uint32_t E         : 1;
56        uint32_t P         : 1;
57        uint32_t C         : 1;
58        uint32_t D         : 1;
59        uint32_t IntEn     : 3;
60        uint32_t SBZ1      : 1;
61        uint32_t Flag      : 3;
62        uint32_t X         : 1;
63        uint32_t EvtCount2 : 8;
64        uint32_t EvtCount1 : 8;
65        uint32_t SBZ2      : 4;
66    };
67    uint32_t raw;
68} sel4bench_arm1136_pmnc_t;
69
70static CACHESENSFN void sel4bench_private_set_pmnc(sel4bench_arm1136_pmnc_t val)
71{
72    /*
73     * The ARM1136 has a 3-cycle delay between changing the PMNC and the
74     * counters reacting. So we insert 3 nops to cover for that. Aligning on a
75     * cache line boundary guarantees that the nops won't cause anything
76     * interesting to happen.
77     */
78    asm volatile (
79        "mcr p15, 0, %0, c15, c12, 0;"
80        "nop;"
81        "nop;"
82        "nop;"
83        :
84        : "r"(val.raw)
85    );
86}
87static FASTFN sel4bench_arm1136_pmnc_t sel4bench_private_get_pmnc(void)
88{
89    sel4bench_arm1136_pmnc_t val;
90    asm volatile (
91        "mrc p15, 0, %0, c15, c12, 0"
92        : "=r"(val.raw)
93        :
94    );
95    return val;
96}
97
98/*
99 * CCNT: cycle counter
100 */
101static FASTFN uint32_t sel4bench_private_get_ccnt()
102{
103    uint32_t val;
104    asm volatile (
105        "mrc p15, 0, %0, c15, c12," SEL4BENCH_ARM1136_COUNTER_CCNT
106        : "=r"(val)
107    );
108    return val;
109}
110
111/*
112 * PMN0: event count 0
113 */
114static FASTFN uint32_t sel4bench_private_get_pmn0()
115{
116    uint32_t val;
117    asm volatile (
118        "mrc p15, 0, %0, c15, c12,"SEL4BENCH_ARM1136_COUNTER_PMN0
119        : "=r"(val)
120    );
121    return val;
122}
123static FASTFN void sel4bench_private_set_pmn0(uint32_t val)
124{
125    asm volatile (
126        "mcr p15, 0, %0, c15, c12,"SEL4BENCH_ARM1136_COUNTER_PMN0
127        : "=r"(val)
128    );
129}
130
131/*
132 * PMN1: event count 1
133 */
134static FASTFN uint32_t sel4bench_private_get_pmn1()
135{
136    uint32_t val;
137    asm volatile (
138        "mrc p15, 0, %0, c15, c12,"SEL4BENCH_ARM1136_COUNTER_PMN1
139        : "=r"(val)
140    );
141    return val;
142}
143static FASTFN void sel4bench_private_set_pmn1(uint32_t val)
144{
145    asm volatile (
146        "mcr p15, 0, %0, c15, c12,"SEL4BENCH_ARM1136_COUNTER_PMN1
147        : "=r"(val)
148    );
149}
150