110461SAndreas.Sandberg@ARM.com/*
212973Sandreas.sandberg@arm.com * Copyright (c) 2011-2014, 2017-2018 ARM Limited
310461SAndreas.Sandberg@ARM.com * All rights reserved
410461SAndreas.Sandberg@ARM.com *
510461SAndreas.Sandberg@ARM.com * The license below extends only to copyright in the software and shall
610461SAndreas.Sandberg@ARM.com * not be construed as granting a license to any other intellectual
710461SAndreas.Sandberg@ARM.com * property including but not limited to intellectual property relating
810461SAndreas.Sandberg@ARM.com * to a hardware implementation of the functionality of the software
910461SAndreas.Sandberg@ARM.com * licensed hereunder.  You may use the software subject to the license
1010461SAndreas.Sandberg@ARM.com * terms below provided that you ensure that this notice is replicated
1110461SAndreas.Sandberg@ARM.com * unmodified and in its entirety in all distributions of the software,
1210461SAndreas.Sandberg@ARM.com * modified or unmodified, in source code or in binary form.
1310461SAndreas.Sandberg@ARM.com *
1410461SAndreas.Sandberg@ARM.com * Redistribution and use in source and binary forms, with or without
1510461SAndreas.Sandberg@ARM.com * modification, are permitted provided that the following conditions are
1610461SAndreas.Sandberg@ARM.com * met: redistributions of source code must retain the above copyright
1710461SAndreas.Sandberg@ARM.com * notice, this list of conditions and the following disclaimer;
1810461SAndreas.Sandberg@ARM.com * redistributions in binary form must reproduce the above copyright
1910461SAndreas.Sandberg@ARM.com * notice, this list of conditions and the following disclaimer in the
2010461SAndreas.Sandberg@ARM.com * documentation and/or other materials provided with the distribution;
2110461SAndreas.Sandberg@ARM.com * neither the name of the copyright holders nor the names of its
2210461SAndreas.Sandberg@ARM.com * contributors may be used to endorse or promote products derived from
2310461SAndreas.Sandberg@ARM.com * this software without specific prior written permission.
2410461SAndreas.Sandberg@ARM.com *
2510461SAndreas.Sandberg@ARM.com * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
2610461SAndreas.Sandberg@ARM.com * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
2710461SAndreas.Sandberg@ARM.com * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
2810461SAndreas.Sandberg@ARM.com * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
2910461SAndreas.Sandberg@ARM.com * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
3010461SAndreas.Sandberg@ARM.com * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
3110461SAndreas.Sandberg@ARM.com * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
3210461SAndreas.Sandberg@ARM.com * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
3310461SAndreas.Sandberg@ARM.com * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
3410461SAndreas.Sandberg@ARM.com * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
3510461SAndreas.Sandberg@ARM.com * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
3610461SAndreas.Sandberg@ARM.com *
3710461SAndreas.Sandberg@ARM.com * Authors: Dam Sunwoo
3810461SAndreas.Sandberg@ARM.com *          Matt Horsnell
3910461SAndreas.Sandberg@ARM.com *          Andreas Sandberg
4010461SAndreas.Sandberg@ARM.com */
4110461SAndreas.Sandberg@ARM.com#ifndef __ARCH_ARM_PMU_HH__
4210461SAndreas.Sandberg@ARM.com#define __ARCH_ARM_PMU_HH__
4310461SAndreas.Sandberg@ARM.com
4410461SAndreas.Sandberg@ARM.com#include <map>
4510461SAndreas.Sandberg@ARM.com#include <memory>
4610461SAndreas.Sandberg@ARM.com#include <vector>
4710461SAndreas.Sandberg@ARM.com
4810461SAndreas.Sandberg@ARM.com#include "arch/arm/isa_device.hh"
4910461SAndreas.Sandberg@ARM.com#include "arch/arm/registers.hh"
5012286Sjose.marinho@arm.com#include "arch/arm/system.hh"
5112286Sjose.marinho@arm.com#include "base/cprintf.hh"
5212286Sjose.marinho@arm.com#include "cpu/base.hh"
5312286Sjose.marinho@arm.com#include "debug/PMUVerbose.hh"
5412286Sjose.marinho@arm.com#include "sim/eventq.hh"
5510461SAndreas.Sandberg@ARM.com#include "sim/sim_object.hh"
5612286Sjose.marinho@arm.com#include "sim/system.hh"
5710461SAndreas.Sandberg@ARM.com
5810461SAndreas.Sandberg@ARM.comclass ArmPMUParams;
5910461SAndreas.Sandberg@ARM.comclass Platform;
6010461SAndreas.Sandberg@ARM.comclass ThreadContext;
6112973Sandreas.sandberg@arm.comclass ArmInterruptPin;
6210461SAndreas.Sandberg@ARM.com
6310461SAndreas.Sandberg@ARM.comnamespace ArmISA {
6410461SAndreas.Sandberg@ARM.com
6510461SAndreas.Sandberg@ARM.com
6610461SAndreas.Sandberg@ARM.com/**
6710461SAndreas.Sandberg@ARM.com * Model of an ARM PMU version 3
6810461SAndreas.Sandberg@ARM.com *
6910461SAndreas.Sandberg@ARM.com * This class implements a subset of the ARM PMU v3 specification as
7010461SAndreas.Sandberg@ARM.com * described in the ARMv8 reference manual. It supports most of the
7110461SAndreas.Sandberg@ARM.com * features of the PMU, however the following features are known to be
7210461SAndreas.Sandberg@ARM.com * missing:
7310461SAndreas.Sandberg@ARM.com *
7410461SAndreas.Sandberg@ARM.com * <ul>
7510461SAndreas.Sandberg@ARM.com *   <li>Event filtering (e.g., from different privilege levels).
7610461SAndreas.Sandberg@ARM.com *   <li>Access controls (the PMU currently ignores the execution level).
7710461SAndreas.Sandberg@ARM.com *   <li>The chain counter (event no. 0x1E) is unimplemented.
7810461SAndreas.Sandberg@ARM.com * </ul>
7910461SAndreas.Sandberg@ARM.com *
8010461SAndreas.Sandberg@ARM.com * The PMU itself does not implement any events, in merely provides an
8110461SAndreas.Sandberg@ARM.com * interface for the configuration scripts to hook up probes that
8210461SAndreas.Sandberg@ARM.com * drive events. Configuration scripts should call addEventProbe() to
8310461SAndreas.Sandberg@ARM.com * configure custom events or high-level methods to configure
8410461SAndreas.Sandberg@ARM.com * architected events. The Python implementation of addEventProbe()
8510461SAndreas.Sandberg@ARM.com * automatically delays event type registration until after
8610461SAndreas.Sandberg@ARM.com * instantiation.
8710461SAndreas.Sandberg@ARM.com *
8810461SAndreas.Sandberg@ARM.com * In order to support CPU switching and some combined counters (e.g.,
8910461SAndreas.Sandberg@ARM.com * memory references synthesized from loads and stores), the PMU
9010461SAndreas.Sandberg@ARM.com * allows multiple probes per event type. When creating a system that
9110461SAndreas.Sandberg@ARM.com * switches between CPU models that share the same PMU, PMU events for
9210461SAndreas.Sandberg@ARM.com * all of the CPU models can be registered with the PMU.
9310461SAndreas.Sandberg@ARM.com *
9410461SAndreas.Sandberg@ARM.com * @see The ARM Architecture Refererence Manual (DDI 0487A)
9510461SAndreas.Sandberg@ARM.com *
9610461SAndreas.Sandberg@ARM.com */
9710461SAndreas.Sandberg@ARM.comclass PMU : public SimObject, public ArmISA::BaseISADevice {
9810461SAndreas.Sandberg@ARM.com  public:
9910461SAndreas.Sandberg@ARM.com    PMU(const ArmPMUParams *p);
10010461SAndreas.Sandberg@ARM.com    ~PMU();
10110461SAndreas.Sandberg@ARM.com
10210461SAndreas.Sandberg@ARM.com    void addEventProbe(unsigned int id, SimObject *obj, const char *name);
10312286Sjose.marinho@arm.com    void addSoftwareIncrementEvent(unsigned int id);
10412286Sjose.marinho@arm.com
10512286Sjose.marinho@arm.com    void registerEvent(uint32_t id);
10610461SAndreas.Sandberg@ARM.com
10710461SAndreas.Sandberg@ARM.com  public: // SimObject and related interfaces
10811168Sandreas.hansson@arm.com    void serialize(CheckpointOut &cp) const override;
10911168Sandreas.hansson@arm.com    void unserialize(CheckpointIn &cp) override;
11010461SAndreas.Sandberg@ARM.com
11111168Sandreas.hansson@arm.com    void drainResume() override;
11210461SAndreas.Sandberg@ARM.com
11312286Sjose.marinho@arm.com    void regProbeListeners() override;
11410461SAndreas.Sandberg@ARM.com
11510461SAndreas.Sandberg@ARM.com  public: // ISA Device interface
11612973Sandreas.sandberg@arm.com    void setThreadContext(ThreadContext *tc) override;
11712973Sandreas.sandberg@arm.com
11810461SAndreas.Sandberg@ARM.com    /**
11910461SAndreas.Sandberg@ARM.com     * Set a register within the PMU.
12010461SAndreas.Sandberg@ARM.com     *
12110461SAndreas.Sandberg@ARM.com     * @param misc_reg Register number (see miscregs.hh)
12210461SAndreas.Sandberg@ARM.com     * @param val Value to store
12310461SAndreas.Sandberg@ARM.com     */
12413581Sgabeblack@google.com    void setMiscReg(int misc_reg, RegVal val) override;
12510461SAndreas.Sandberg@ARM.com    /**
12610461SAndreas.Sandberg@ARM.com     * Read a register within the PMU.
12710461SAndreas.Sandberg@ARM.com     *
12810461SAndreas.Sandberg@ARM.com     * @param misc_reg Register number (see miscregs.hh)
12910461SAndreas.Sandberg@ARM.com     * @return Register value.
13010461SAndreas.Sandberg@ARM.com     */
13113581Sgabeblack@google.com    RegVal readMiscReg(int misc_reg) override;
13210461SAndreas.Sandberg@ARM.com
13310461SAndreas.Sandberg@ARM.com  protected: // PMU register types and constants
13410461SAndreas.Sandberg@ARM.com    BitUnion32(PMCR_t)
13510461SAndreas.Sandberg@ARM.com        // PMU Enable
13610461SAndreas.Sandberg@ARM.com        Bitfield<0> e;
13710461SAndreas.Sandberg@ARM.com        // Event counter reset
13810461SAndreas.Sandberg@ARM.com        Bitfield<1> p;
13910461SAndreas.Sandberg@ARM.com        // Cycle counter reset
14010461SAndreas.Sandberg@ARM.com        Bitfield<2> c;
14110461SAndreas.Sandberg@ARM.com        // Cycle counter divider enable
14210461SAndreas.Sandberg@ARM.com        Bitfield<3> d;
14310461SAndreas.Sandberg@ARM.com        // Export enable
14410461SAndreas.Sandberg@ARM.com        Bitfield<4> x;
14510461SAndreas.Sandberg@ARM.com        // Disable PMCCNTR when event counting is prohibited
14610461SAndreas.Sandberg@ARM.com        Bitfield<5> dp;
14710461SAndreas.Sandberg@ARM.com        // Long Cycle counter enable
14810461SAndreas.Sandberg@ARM.com        Bitfield<6> lc;
14910461SAndreas.Sandberg@ARM.com        // Number of event counters implemented
15010461SAndreas.Sandberg@ARM.com        Bitfield<15, 11> n;
15110461SAndreas.Sandberg@ARM.com        // Implementation ID
15210461SAndreas.Sandberg@ARM.com        Bitfield<23, 16> idcode;
15310461SAndreas.Sandberg@ARM.com        // Implementer code
15410461SAndreas.Sandberg@ARM.com        Bitfield<31, 24> imp;
15510461SAndreas.Sandberg@ARM.com    EndBitUnion(PMCR_t)
15610461SAndreas.Sandberg@ARM.com
15710461SAndreas.Sandberg@ARM.com    BitUnion32(PMSELR_t)
15810461SAndreas.Sandberg@ARM.com        // Performance counter selector
15910461SAndreas.Sandberg@ARM.com        Bitfield<4, 0> sel;
16010461SAndreas.Sandberg@ARM.com    EndBitUnion(PMSELR_t)
16110461SAndreas.Sandberg@ARM.com
16210461SAndreas.Sandberg@ARM.com    BitUnion32(PMEVTYPER_t)
16312117Sjose.marinho@arm.com        Bitfield<15, 0> evtCount;
16410461SAndreas.Sandberg@ARM.com
16510461SAndreas.Sandberg@ARM.com        // Secure EL3 filtering
16610461SAndreas.Sandberg@ARM.com        Bitfield<26> m;
16710461SAndreas.Sandberg@ARM.com        // Non-secure EL2 mode filtering
16810461SAndreas.Sandberg@ARM.com        Bitfield<27> nsh;
16910461SAndreas.Sandberg@ARM.com        // Non-secure EL0 mode filtering
17010461SAndreas.Sandberg@ARM.com        Bitfield<28> nsu;
17110461SAndreas.Sandberg@ARM.com        // Non-secure EL1 mode filtering
17210461SAndreas.Sandberg@ARM.com        Bitfield<29> nsk;
17310461SAndreas.Sandberg@ARM.com        // EL0 filtering
17410461SAndreas.Sandberg@ARM.com        Bitfield<30> u;
17510461SAndreas.Sandberg@ARM.com        // EL1 filtering
17610461SAndreas.Sandberg@ARM.com        Bitfield<31> p;
17710461SAndreas.Sandberg@ARM.com    EndBitUnion(PMEVTYPER_t)
17810461SAndreas.Sandberg@ARM.com
17910461SAndreas.Sandberg@ARM.com    /**
18010461SAndreas.Sandberg@ARM.com     * Counter ID within the PMU.
18110461SAndreas.Sandberg@ARM.com     *
18210461SAndreas.Sandberg@ARM.com     * This value is typically used to index into various registers
18310461SAndreas.Sandberg@ARM.com     * controlling interrupts and overflows. The value normally in the
18410461SAndreas.Sandberg@ARM.com     * [0, 31] range, where 31 refers to the cycle counter.
18510461SAndreas.Sandberg@ARM.com     */
18610461SAndreas.Sandberg@ARM.com    typedef unsigned int CounterId;
18710461SAndreas.Sandberg@ARM.com
18810461SAndreas.Sandberg@ARM.com    /** Cycle Count Register Number */
18910461SAndreas.Sandberg@ARM.com    static const CounterId PMCCNTR = 31;
19010461SAndreas.Sandberg@ARM.com
19110461SAndreas.Sandberg@ARM.com    /**
19210461SAndreas.Sandberg@ARM.com     * Event type ID.
19310461SAndreas.Sandberg@ARM.com     *
19410461SAndreas.Sandberg@ARM.com     * See the PMU documentation for a list of architected IDs.
19510461SAndreas.Sandberg@ARM.com     */
19610461SAndreas.Sandberg@ARM.com    typedef unsigned int EventTypeId;
19710461SAndreas.Sandberg@ARM.com
19810461SAndreas.Sandberg@ARM.com  protected: /* High-level register and interrupt handling */
19913581Sgabeblack@google.com    RegVal readMiscRegInt(int misc_reg);
20010461SAndreas.Sandberg@ARM.com
20110461SAndreas.Sandberg@ARM.com    /**
20210461SAndreas.Sandberg@ARM.com     * PMCR write handling
20310461SAndreas.Sandberg@ARM.com     *
20410461SAndreas.Sandberg@ARM.com     * The PMCR register needs special handling since writing to it
20510461SAndreas.Sandberg@ARM.com     * changes PMU-global state (e.g., resets all counters).
20610461SAndreas.Sandberg@ARM.com     *
20710461SAndreas.Sandberg@ARM.com     * @param val New PMCR value
20810461SAndreas.Sandberg@ARM.com     */
20910461SAndreas.Sandberg@ARM.com    void setControlReg(PMCR_t val);
21010461SAndreas.Sandberg@ARM.com
21110461SAndreas.Sandberg@ARM.com    /**
21210461SAndreas.Sandberg@ARM.com     * Reset all event counters excluding the cycle counter to zero.
21310461SAndreas.Sandberg@ARM.com     */
21410461SAndreas.Sandberg@ARM.com    void resetEventCounts();
21510461SAndreas.Sandberg@ARM.com
21610461SAndreas.Sandberg@ARM.com    /**
21710461SAndreas.Sandberg@ARM.com     * Deliver a PMU interrupt to the GIC
21810461SAndreas.Sandberg@ARM.com     */
21910461SAndreas.Sandberg@ARM.com    void raiseInterrupt();
22010461SAndreas.Sandberg@ARM.com
22110461SAndreas.Sandberg@ARM.com    /**
22213104Sgiacomo.travaglini@arm.com     * Clear a PMU interrupt.
22313104Sgiacomo.travaglini@arm.com     */
22413104Sgiacomo.travaglini@arm.com    void clearInterrupt();
22513104Sgiacomo.travaglini@arm.com
22613104Sgiacomo.travaglini@arm.com    /**
22710461SAndreas.Sandberg@ARM.com     * Get the value of a performance counter.
22810461SAndreas.Sandberg@ARM.com     *
22910461SAndreas.Sandberg@ARM.com     * This method returns the value of a general purpose performance
23010461SAndreas.Sandberg@ARM.com     * counter or the fixed-function cycle counter. Non-existing
23110461SAndreas.Sandberg@ARM.com     * counters are treated as constant '0'.
23210461SAndreas.Sandberg@ARM.com     *
23310461SAndreas.Sandberg@ARM.com     * @return Value of the performance counter, 0 if the counter does
23410461SAndreas.Sandberg@ARM.com     * not exist.
23510461SAndreas.Sandberg@ARM.com     */
23610461SAndreas.Sandberg@ARM.com    uint64_t getCounterValue(CounterId id) const {
23712286Sjose.marinho@arm.com        return isValidCounter(id) ? getCounter(id).getValue() : 0;
23810461SAndreas.Sandberg@ARM.com    }
23910461SAndreas.Sandberg@ARM.com
24010461SAndreas.Sandberg@ARM.com    /**
24110461SAndreas.Sandberg@ARM.com     * Set the value of a performance counter.
24210461SAndreas.Sandberg@ARM.com     *
24310461SAndreas.Sandberg@ARM.com     * This method sets the value of a general purpose performance
24410461SAndreas.Sandberg@ARM.com     * counter or the fixed-function cycle counter. Writes to
24510461SAndreas.Sandberg@ARM.com     * non-existing counters are ignored.
24610461SAndreas.Sandberg@ARM.com     */
24710461SAndreas.Sandberg@ARM.com    void setCounterValue(CounterId id, uint64_t val);
24810461SAndreas.Sandberg@ARM.com
24910461SAndreas.Sandberg@ARM.com    /**
25010461SAndreas.Sandberg@ARM.com     * Get the type and filter settings of a counter (PMEVTYPER)
25110461SAndreas.Sandberg@ARM.com     *
25210461SAndreas.Sandberg@ARM.com     * This method implements a read from a PMEVTYPER register. It
25310461SAndreas.Sandberg@ARM.com     * returns the type value and filter settings of a general purpose
25410461SAndreas.Sandberg@ARM.com     * performance counter or the cycle counter. Non-existing counters
25510461SAndreas.Sandberg@ARM.com     * are treated as constant '0'.
25610461SAndreas.Sandberg@ARM.com     *
25710461SAndreas.Sandberg@ARM.com     * @param id Counter ID within the PMU.
25810461SAndreas.Sandberg@ARM.com     * @return Performance counter type ID.
25910461SAndreas.Sandberg@ARM.com     */
26010461SAndreas.Sandberg@ARM.com    PMEVTYPER_t getCounterTypeRegister(CounterId id) const;
26110461SAndreas.Sandberg@ARM.com
26210461SAndreas.Sandberg@ARM.com    /**
26310461SAndreas.Sandberg@ARM.com     * Set the type and filter settings of a performance counter
26410461SAndreas.Sandberg@ARM.com     * (PMEVTYPER)
26510461SAndreas.Sandberg@ARM.com     *
26610461SAndreas.Sandberg@ARM.com     * This method implements a write to a PMEVTYPER register. It sets
26710461SAndreas.Sandberg@ARM.com     * the type value and filter settings of a general purpose
26810461SAndreas.Sandberg@ARM.com     * performance counter or the cycle counter. Writes to
26910461SAndreas.Sandberg@ARM.com     * non-existing counters are ignored. The method automatically
27010461SAndreas.Sandberg@ARM.com     * updates the probes used by the counter if it is enabled.
27110461SAndreas.Sandberg@ARM.com     *
27210461SAndreas.Sandberg@ARM.com     * @param id Counter ID within the PMU.
27310461SAndreas.Sandberg@ARM.com     * @param type Performance counter type and filter configuration..
27410461SAndreas.Sandberg@ARM.com     */
27510461SAndreas.Sandberg@ARM.com    void setCounterTypeRegister(CounterId id, PMEVTYPER_t type);
27610461SAndreas.Sandberg@ARM.com
27713104Sgiacomo.travaglini@arm.com    /**
27813104Sgiacomo.travaglini@arm.com     * Used for writing the Overflow Flag Status Register (SET/CLR)
27913104Sgiacomo.travaglini@arm.com     *
28013104Sgiacomo.travaglini@arm.com     * This method implements a write to the PMOVSSET/PMOVSCLR registers.
28113104Sgiacomo.travaglini@arm.com     * It is capturing change of state in the register bits so that
28213104Sgiacomo.travaglini@arm.com     * the overflow interrupt can be raised/cleared as a side effect
28313104Sgiacomo.travaglini@arm.com     * of the write.
28413104Sgiacomo.travaglini@arm.com     *
28513104Sgiacomo.travaglini@arm.com     * @param new_val New value of the Overflow Status Register
28613104Sgiacomo.travaglini@arm.com     */
28713581Sgabeblack@google.com    void setOverflowStatus(RegVal new_val);
28813104Sgiacomo.travaglini@arm.com
28910461SAndreas.Sandberg@ARM.com  protected: /* Probe handling and counter state */
29012286Sjose.marinho@arm.com    struct CounterState;
29110461SAndreas.Sandberg@ARM.com
29212286Sjose.marinho@arm.com    /**
29312286Sjose.marinho@arm.com     * Event definition base class
29412286Sjose.marinho@arm.com     */
29512286Sjose.marinho@arm.com    struct PMUEvent {
29612286Sjose.marinho@arm.com
29712286Sjose.marinho@arm.com        PMUEvent() {}
29812286Sjose.marinho@arm.com
29912286Sjose.marinho@arm.com        virtual ~PMUEvent() {}
30012286Sjose.marinho@arm.com
30112286Sjose.marinho@arm.com        /**
30212286Sjose.marinho@arm.com         * attach this event to a given counter
30312286Sjose.marinho@arm.com         *
30412286Sjose.marinho@arm.com         * @param a pointer to the counter where to attach this event
30512286Sjose.marinho@arm.com         */
30612286Sjose.marinho@arm.com        void attachEvent(PMU::CounterState *user);
30712286Sjose.marinho@arm.com
30812286Sjose.marinho@arm.com        /**
30912286Sjose.marinho@arm.com         * detach this event from a given counter
31012286Sjose.marinho@arm.com         *
31112286Sjose.marinho@arm.com         * @param a pointer to the counter where to detach this event from
31212286Sjose.marinho@arm.com         */
31312286Sjose.marinho@arm.com        void detachEvent(PMU::CounterState *user);
31412286Sjose.marinho@arm.com
31512286Sjose.marinho@arm.com        /**
31612286Sjose.marinho@arm.com         * notify an event increment of val units, all the attached counters'
31712286Sjose.marinho@arm.com         * value is incremented by val units.
31812286Sjose.marinho@arm.com         *
31912286Sjose.marinho@arm.com         * @param the quantity by which to increment the attached counter
32012286Sjose.marinho@arm.com         * values
32112286Sjose.marinho@arm.com         */
32212286Sjose.marinho@arm.com        virtual void increment(const uint64_t val);
32312286Sjose.marinho@arm.com
32412286Sjose.marinho@arm.com        /**
32512286Sjose.marinho@arm.com         * Enable the current event
32612286Sjose.marinho@arm.com         */
32712286Sjose.marinho@arm.com        virtual void enable() = 0;
32812286Sjose.marinho@arm.com
32912286Sjose.marinho@arm.com        /**
33012286Sjose.marinho@arm.com         * Disable the current event
33112286Sjose.marinho@arm.com         */
33212286Sjose.marinho@arm.com        virtual void disable() = 0;
33312286Sjose.marinho@arm.com
33412286Sjose.marinho@arm.com        /**
33512286Sjose.marinho@arm.com         *  Method called immediately before a counter access in order for
33612286Sjose.marinho@arm.com         *  the associated event to update its state (if required)
33712286Sjose.marinho@arm.com         */
33812286Sjose.marinho@arm.com        virtual void updateAttachedCounters() {}
33912286Sjose.marinho@arm.com
34012286Sjose.marinho@arm.com      protected:
34112286Sjose.marinho@arm.com
34212286Sjose.marinho@arm.com        /** set of counters using this event  **/
34312286Sjose.marinho@arm.com        std::set<PMU::CounterState*> userCounters;
34412286Sjose.marinho@arm.com    };
34512286Sjose.marinho@arm.com
34612286Sjose.marinho@arm.com    struct RegularEvent : public PMUEvent {
34712286Sjose.marinho@arm.com        typedef std::pair<SimObject*, std::string> EventTypeEntry;
34812286Sjose.marinho@arm.com
34912286Sjose.marinho@arm.com        void addMicroarchitectureProbe(SimObject* object,
35012286Sjose.marinho@arm.com            std::string name) {
35112286Sjose.marinho@arm.com
35212286Sjose.marinho@arm.com            panic_if(!object,"malformed probe-point"
35312286Sjose.marinho@arm.com                " definition with name %s\n", name);
35412286Sjose.marinho@arm.com
35512286Sjose.marinho@arm.com            microArchitectureEventSet.emplace(object, name);
35610461SAndreas.Sandberg@ARM.com        }
35710461SAndreas.Sandberg@ARM.com
35810461SAndreas.Sandberg@ARM.com      protected:
35912286Sjose.marinho@arm.com        struct RegularProbe: public  ProbeListenerArgBase<uint64_t>
36012286Sjose.marinho@arm.com        {
36112286Sjose.marinho@arm.com            RegularProbe(RegularEvent *parent, SimObject* obj,
36212286Sjose.marinho@arm.com                std::string name)
36312286Sjose.marinho@arm.com                : ProbeListenerArgBase(obj->getProbeManager(), name),
36412286Sjose.marinho@arm.com                  parentEvent(parent) {}
36512286Sjose.marinho@arm.com
36612286Sjose.marinho@arm.com            RegularProbe() = delete;
36712286Sjose.marinho@arm.com
36812286Sjose.marinho@arm.com            void notify(const uint64_t &val);
36912286Sjose.marinho@arm.com
37012286Sjose.marinho@arm.com          protected:
37112286Sjose.marinho@arm.com            RegularEvent *parentEvent;
37212286Sjose.marinho@arm.com        };
37312286Sjose.marinho@arm.com
37412286Sjose.marinho@arm.com        /** The set of events driving the event value **/
37512286Sjose.marinho@arm.com        std::set<EventTypeEntry> microArchitectureEventSet;
37612286Sjose.marinho@arm.com
37712286Sjose.marinho@arm.com        /** Set of probe listeners tapping onto each of the input micro-arch
37812286Sjose.marinho@arm.com         *  events which compose this pmu event
37912286Sjose.marinho@arm.com         */
38012286Sjose.marinho@arm.com        std::vector<std::unique_ptr<RegularProbe>> attachedProbePointList;
38112286Sjose.marinho@arm.com
38212286Sjose.marinho@arm.com        void enable() override;
38312286Sjose.marinho@arm.com
38412286Sjose.marinho@arm.com        void disable() override;
38510461SAndreas.Sandberg@ARM.com    };
38612286Sjose.marinho@arm.com
38712286Sjose.marinho@arm.com    class SWIncrementEvent : public PMUEvent
38812286Sjose.marinho@arm.com    {
38912286Sjose.marinho@arm.com        void enable() override {}
39012286Sjose.marinho@arm.com        void disable() override {}
39112286Sjose.marinho@arm.com
39212286Sjose.marinho@arm.com      public:
39312286Sjose.marinho@arm.com
39412286Sjose.marinho@arm.com        /**
39512286Sjose.marinho@arm.com         * write on the sw increment register inducing an increment of the
39612286Sjose.marinho@arm.com         * counters with this event selected according to the bitfield written.
39712286Sjose.marinho@arm.com         *
39812286Sjose.marinho@arm.com         * @param the bitfield selecting the counters to increment.
39912286Sjose.marinho@arm.com         */
40012286Sjose.marinho@arm.com        void write(uint64_t val);
40112286Sjose.marinho@arm.com    };
40210461SAndreas.Sandberg@ARM.com
40310461SAndreas.Sandberg@ARM.com    /**
40412286Sjose.marinho@arm.com     * Obtain the event of a given id
40510461SAndreas.Sandberg@ARM.com     *
40612286Sjose.marinho@arm.com     * @param the id of the event to obtain
40712286Sjose.marinho@arm.com     * @return a pointer to the event with id eventId
40810461SAndreas.Sandberg@ARM.com     */
40912286Sjose.marinho@arm.com    PMUEvent* getEvent(uint64_t eventId);
41010461SAndreas.Sandberg@ARM.com
41112286Sjose.marinho@arm.com    /** State of a counter within the PMU. **/
41210905Sandreas.sandberg@arm.com    struct CounterState : public Serializable {
41312286Sjose.marinho@arm.com        CounterState(PMU &pmuReference, uint64_t counter_id)
41412286Sjose.marinho@arm.com            : eventId(0), filter(0), enabled(false),
41512286Sjose.marinho@arm.com              overflow64(false), sourceEvent(nullptr),
41612286Sjose.marinho@arm.com              counterId(counter_id), value(0), resetValue(false),
41712286Sjose.marinho@arm.com              pmu(pmuReference) {}
41810461SAndreas.Sandberg@ARM.com
41911168Sandreas.hansson@arm.com        void serialize(CheckpointOut &cp) const override;
42011168Sandreas.hansson@arm.com        void unserialize(CheckpointIn &cp)  override;
42110461SAndreas.Sandberg@ARM.com
42210461SAndreas.Sandberg@ARM.com        /**
42310461SAndreas.Sandberg@ARM.com         * Add an event count to the counter and check for overflow.
42410461SAndreas.Sandberg@ARM.com         *
42510461SAndreas.Sandberg@ARM.com         * @param delta Number of events to add to the counter.
42612286Sjose.marinho@arm.com         * @return the quantity remaining until a counter overflow occurs.
42710461SAndreas.Sandberg@ARM.com         */
42812286Sjose.marinho@arm.com        uint64_t add(uint64_t delta);
42912286Sjose.marinho@arm.com
43012286Sjose.marinho@arm.com        bool isFiltered() const;
43112286Sjose.marinho@arm.com
43212286Sjose.marinho@arm.com        /**
43312286Sjose.marinho@arm.com         * Detach the counter from its event
43412286Sjose.marinho@arm.com         */
43512286Sjose.marinho@arm.com        void detach();
43612286Sjose.marinho@arm.com
43712286Sjose.marinho@arm.com        /**
43812286Sjose.marinho@arm.com         * Attach this counter to an event
43912286Sjose.marinho@arm.com         *
44012286Sjose.marinho@arm.com         * @param the event to attach the counter to
44112286Sjose.marinho@arm.com         */
44212286Sjose.marinho@arm.com        void attach(PMUEvent* event);
44312286Sjose.marinho@arm.com
44412286Sjose.marinho@arm.com        /**
44512286Sjose.marinho@arm.com         * Obtain the counter id
44612286Sjose.marinho@arm.com         *
44712286Sjose.marinho@arm.com         * @return the pysical counter id
44812286Sjose.marinho@arm.com         */
44912286Sjose.marinho@arm.com        uint64_t getCounterId() const{
45012286Sjose.marinho@arm.com            return counterId;
45112286Sjose.marinho@arm.com        }
45212286Sjose.marinho@arm.com
45312286Sjose.marinho@arm.com        /**
45412286Sjose.marinho@arm.com         * rReturn the counter value
45512286Sjose.marinho@arm.com         *
45612286Sjose.marinho@arm.com         * @return the counter value
45712286Sjose.marinho@arm.com         */
45812286Sjose.marinho@arm.com        uint64_t getValue() const;
45912286Sjose.marinho@arm.com
46012286Sjose.marinho@arm.com        /**
46112286Sjose.marinho@arm.com         * overwrite the value of the counter
46212286Sjose.marinho@arm.com         *
46312286Sjose.marinho@arm.com         * @param the new counter value
46412286Sjose.marinho@arm.com         */
46512286Sjose.marinho@arm.com        void setValue(uint64_t val);
46610461SAndreas.Sandberg@ARM.com
46710461SAndreas.Sandberg@ARM.com      public: /* Serializable state */
46810461SAndreas.Sandberg@ARM.com        /** Counter event ID */
46910461SAndreas.Sandberg@ARM.com        EventTypeId eventId;
47010461SAndreas.Sandberg@ARM.com
47110609Sandreas.sandberg@arm.com        /** Filtering settings (evtCount is unused) */
47210609Sandreas.sandberg@arm.com        PMEVTYPER_t filter;
47310609Sandreas.sandberg@arm.com
47410461SAndreas.Sandberg@ARM.com        /** Is the counter enabled? */
47510461SAndreas.Sandberg@ARM.com        bool enabled;
47610461SAndreas.Sandberg@ARM.com
47710461SAndreas.Sandberg@ARM.com        /** Is this a 64-bit counter? */
47810461SAndreas.Sandberg@ARM.com        bool overflow64;
47910461SAndreas.Sandberg@ARM.com
48012286Sjose.marinho@arm.com      protected: /* Configuration */
48112286Sjose.marinho@arm.com        /** PmuEvent currently in use (if any) **/
48212286Sjose.marinho@arm.com        PMUEvent *sourceEvent;
48312286Sjose.marinho@arm.com
48412286Sjose.marinho@arm.com        /** id of the counter instance **/
48512286Sjose.marinho@arm.com        uint64_t counterId;
48612286Sjose.marinho@arm.com
48712286Sjose.marinho@arm.com        /** Current value of the counter */
48812286Sjose.marinho@arm.com        uint64_t value;
48912286Sjose.marinho@arm.com
49012286Sjose.marinho@arm.com        /** Flag keeping track if the counter has been reset **/
49112286Sjose.marinho@arm.com        bool resetValue;
49212286Sjose.marinho@arm.com
49312286Sjose.marinho@arm.com        PMU &pmu;
49412286Sjose.marinho@arm.com
49512286Sjose.marinho@arm.com        template <typename ...Args>
49612286Sjose.marinho@arm.com        void debugCounter(const char* mainString, Args &...args) const {
49712286Sjose.marinho@arm.com
49812286Sjose.marinho@arm.com            std::string userString = csprintf(mainString, args...);
49912286Sjose.marinho@arm.com
50012286Sjose.marinho@arm.com            warn("[counterId = %d, eventId = %d, sourceEvent = 0x%x] %s",
50112286Sjose.marinho@arm.com                counterId, eventId, sourceEvent, userString.c_str());
50212286Sjose.marinho@arm.com
50312286Sjose.marinho@arm.com        }
50410461SAndreas.Sandberg@ARM.com    };
50510461SAndreas.Sandberg@ARM.com
50610461SAndreas.Sandberg@ARM.com    /**
50710461SAndreas.Sandberg@ARM.com     * Is this a valid counter ID?
50810461SAndreas.Sandberg@ARM.com     *
50910461SAndreas.Sandberg@ARM.com     * @param id ID of counter within the PMU.
51010461SAndreas.Sandberg@ARM.com     *
51110461SAndreas.Sandberg@ARM.com     * @return true if counter is within the allowed range or the
51210461SAndreas.Sandberg@ARM.com     * cycle counter, false otherwise.
51310461SAndreas.Sandberg@ARM.com     */
51410461SAndreas.Sandberg@ARM.com    bool isValidCounter(CounterId id) const {
51510461SAndreas.Sandberg@ARM.com        return id < counters.size() || id == PMCCNTR;
51610461SAndreas.Sandberg@ARM.com    }
51710461SAndreas.Sandberg@ARM.com
51810461SAndreas.Sandberg@ARM.com    /**
51910461SAndreas.Sandberg@ARM.com     * Return the state of a counter.
52010461SAndreas.Sandberg@ARM.com     *
52110461SAndreas.Sandberg@ARM.com     * @param id ID of counter within the PMU.
52210461SAndreas.Sandberg@ARM.com     * @return Reference to a CounterState instance representing the
52310461SAndreas.Sandberg@ARM.com     * counter.
52410461SAndreas.Sandberg@ARM.com     */
52510461SAndreas.Sandberg@ARM.com    CounterState &getCounter(CounterId id) {
52610461SAndreas.Sandberg@ARM.com        assert(isValidCounter(id));
52710461SAndreas.Sandberg@ARM.com        return id == PMCCNTR ? cycleCounter : counters[id];
52810461SAndreas.Sandberg@ARM.com    }
52910461SAndreas.Sandberg@ARM.com
53010461SAndreas.Sandberg@ARM.com    /**
53110461SAndreas.Sandberg@ARM.com     * Return the state of a counter.
53210461SAndreas.Sandberg@ARM.com     *
53310461SAndreas.Sandberg@ARM.com     * @param id ID of counter within the PMU.
53410461SAndreas.Sandberg@ARM.com     * @return Reference to a CounterState instance representing the
53510461SAndreas.Sandberg@ARM.com     * counter.
53610461SAndreas.Sandberg@ARM.com     */
53710461SAndreas.Sandberg@ARM.com    const CounterState &getCounter(CounterId id) const {
53810461SAndreas.Sandberg@ARM.com        assert(isValidCounter(id));
53910461SAndreas.Sandberg@ARM.com        return id == PMCCNTR ? cycleCounter : counters[id];
54010461SAndreas.Sandberg@ARM.com    }
54110461SAndreas.Sandberg@ARM.com
54210461SAndreas.Sandberg@ARM.com    /**
54310461SAndreas.Sandberg@ARM.com     * Depending on counter configuration, add or remove the probes
54410461SAndreas.Sandberg@ARM.com     * driving the counter.
54510461SAndreas.Sandberg@ARM.com     *
54610461SAndreas.Sandberg@ARM.com     * Look at the state of a counter and (re-)attach the probes
54710461SAndreas.Sandberg@ARM.com     * needed to drive a counter if it is currently active. All probes
54810461SAndreas.Sandberg@ARM.com     * for the counter are detached if the counter is inactive.
54910461SAndreas.Sandberg@ARM.com     *
55010461SAndreas.Sandberg@ARM.com     * @param id ID of counter within the PMU.
55110461SAndreas.Sandberg@ARM.com     * @param ctr Reference to the counter's state
55210461SAndreas.Sandberg@ARM.com     */
55312286Sjose.marinho@arm.com    void updateCounter(CounterState &ctr);
55410461SAndreas.Sandberg@ARM.com
55510461SAndreas.Sandberg@ARM.com    /**
55610609Sandreas.sandberg@arm.com     * Check if a counter's settings allow it to be counted.
55710609Sandreas.sandberg@arm.com     *
55810609Sandreas.sandberg@arm.com     * @param ctr Counter state instance representing this counter.
55910609Sandreas.sandberg@arm.com     * @return false if the counter is active, true otherwise.
56010609Sandreas.sandberg@arm.com     */
56110609Sandreas.sandberg@arm.com    bool isFiltered(const CounterState &ctr) const;
56210609Sandreas.sandberg@arm.com
56310609Sandreas.sandberg@arm.com    /**
56410461SAndreas.Sandberg@ARM.com     * Call updateCounter() for each counter in the PMU if the
56510461SAndreas.Sandberg@ARM.com     * counter's state has changed..
56610461SAndreas.Sandberg@ARM.com     *
56710461SAndreas.Sandberg@ARM.com     * @see updateCounter()
56810461SAndreas.Sandberg@ARM.com     */
56910461SAndreas.Sandberg@ARM.com    void updateAllCounters();
57010461SAndreas.Sandberg@ARM.com
57110461SAndreas.Sandberg@ARM.com  protected: /* State that needs to be serialized */
57210461SAndreas.Sandberg@ARM.com    /** Performance Monitor Count Enable Register */
57313581Sgabeblack@google.com    RegVal reg_pmcnten;
57410461SAndreas.Sandberg@ARM.com
57510461SAndreas.Sandberg@ARM.com    /** Performance Monitor Control Register */
57610461SAndreas.Sandberg@ARM.com    PMCR_t reg_pmcr;
57710461SAndreas.Sandberg@ARM.com
57810461SAndreas.Sandberg@ARM.com    /** Performance Monitor Selection Register */
57910461SAndreas.Sandberg@ARM.com    PMSELR_t reg_pmselr;
58010461SAndreas.Sandberg@ARM.com
58110461SAndreas.Sandberg@ARM.com    /** Performance Monitor Interrupt Enable Register */
58213581Sgabeblack@google.com    RegVal reg_pminten;
58310461SAndreas.Sandberg@ARM.com
58410461SAndreas.Sandberg@ARM.com    /** Performance Monitor Overflow Status Register */
58513581Sgabeblack@google.com    RegVal reg_pmovsr;
58610461SAndreas.Sandberg@ARM.com
58710461SAndreas.Sandberg@ARM.com    /**
58810461SAndreas.Sandberg@ARM.com     * Performance counter ID register
58910461SAndreas.Sandberg@ARM.com     *
59012117Sjose.marinho@arm.com     * These registers contain a bitmask of available architected
59110461SAndreas.Sandberg@ARM.com     * counters.
59210461SAndreas.Sandberg@ARM.com     */
59312117Sjose.marinho@arm.com    uint64_t reg_pmceid0;
59412117Sjose.marinho@arm.com    uint64_t reg_pmceid1;
59510461SAndreas.Sandberg@ARM.com
59610461SAndreas.Sandberg@ARM.com    /** Remainder part when the clock counter is divided by 64 */
59710461SAndreas.Sandberg@ARM.com    unsigned clock_remainder;
59810461SAndreas.Sandberg@ARM.com
59912286Sjose.marinho@arm.com    /** The number of regular event counters **/
60012286Sjose.marinho@arm.com    uint64_t maximumCounterCount;
60112286Sjose.marinho@arm.com
60210461SAndreas.Sandberg@ARM.com    /** State of all general-purpose counters supported by PMU */
60310461SAndreas.Sandberg@ARM.com    std::vector<CounterState> counters;
60412286Sjose.marinho@arm.com
60510461SAndreas.Sandberg@ARM.com    /** State of the cycle counter */
60610461SAndreas.Sandberg@ARM.com    CounterState cycleCounter;
60710461SAndreas.Sandberg@ARM.com
60812286Sjose.marinho@arm.com    /** The id of the counter hardwired to the cpu cycle counter **/
60912286Sjose.marinho@arm.com    const uint64_t cycleCounterEventId;
61012286Sjose.marinho@arm.com
61112286Sjose.marinho@arm.com    /** The event that implements the software increment **/
61212286Sjose.marinho@arm.com    SWIncrementEvent *swIncrementEvent;
61312286Sjose.marinho@arm.com
61410461SAndreas.Sandberg@ARM.com  protected: /* Configuration and constants */
61510461SAndreas.Sandberg@ARM.com    /** Constant (configuration-dependent) part of the PMCR */
61610461SAndreas.Sandberg@ARM.com    PMCR_t reg_pmcr_conf;
61712286Sjose.marinho@arm.com
61810461SAndreas.Sandberg@ARM.com    /** PMCR write mask when accessed from the guest */
61913581Sgabeblack@google.com    static const RegVal reg_pmcr_wr_mask;
62010461SAndreas.Sandberg@ARM.com
62110461SAndreas.Sandberg@ARM.com    /** Performance monitor interrupt number */
62213638Sgiacomo.travaglini@arm.com    ArmInterruptPin *interrupt;
62310461SAndreas.Sandberg@ARM.com
62410461SAndreas.Sandberg@ARM.com    /**
62512286Sjose.marinho@arm.com     * List of event types supported by this PMU.
62610461SAndreas.Sandberg@ARM.com     */
62712286Sjose.marinho@arm.com    std::map<EventTypeId, PMUEvent*> eventMap;
62810461SAndreas.Sandberg@ARM.com};
62910461SAndreas.Sandberg@ARM.com
63010461SAndreas.Sandberg@ARM.com} // namespace ArmISA
63110461SAndreas.Sandberg@ARM.com#endif
632