19793Sakash.bagdia@arm.com/*
210249Sstephan.diestelhorst@arm.com * Copyright (c) 2013-2014 ARM Limited
310000Sclt67@cornell.edu * Copyright (c) 2013 Cornell University
49793Sakash.bagdia@arm.com * All rights reserved
59793Sakash.bagdia@arm.com *
69793Sakash.bagdia@arm.com * The license below extends only to copyright in the software and shall
79793Sakash.bagdia@arm.com * not be construed as granting a license to any other intellectual
89793Sakash.bagdia@arm.com * property including but not limited to intellectual property relating
99793Sakash.bagdia@arm.com * to a hardware implementation of the functionality of the software
109793Sakash.bagdia@arm.com * licensed hereunder.  You may use the software subject to the license
119793Sakash.bagdia@arm.com * terms below provided that you ensure that this notice is replicated
129793Sakash.bagdia@arm.com * unmodified and in its entirety in all distributions of the software,
139793Sakash.bagdia@arm.com * modified or unmodified, in source code or in binary form.
149793Sakash.bagdia@arm.com *
159793Sakash.bagdia@arm.com * Redistribution and use in source and binary forms, with or without
169793Sakash.bagdia@arm.com * modification, are permitted provided that the following conditions are
179793Sakash.bagdia@arm.com * met: redistributions of source code must retain the above copyright
189793Sakash.bagdia@arm.com * notice, this list of conditions and the following disclaimer;
199793Sakash.bagdia@arm.com * redistributions in binary form must reproduce the above copyright
209793Sakash.bagdia@arm.com * notice, this list of conditions and the following disclaimer in the
219793Sakash.bagdia@arm.com * documentation and/or other materials provided with the distribution;
229793Sakash.bagdia@arm.com * neither the name of the copyright holders nor the names of its
239793Sakash.bagdia@arm.com * contributors may be used to endorse or promote products derived from
249793Sakash.bagdia@arm.com * this software without specific prior written permission.
259793Sakash.bagdia@arm.com *
269793Sakash.bagdia@arm.com * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
279793Sakash.bagdia@arm.com * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
289793Sakash.bagdia@arm.com * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
299793Sakash.bagdia@arm.com * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
309793Sakash.bagdia@arm.com * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
319793Sakash.bagdia@arm.com * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
329793Sakash.bagdia@arm.com * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
339793Sakash.bagdia@arm.com * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
349793Sakash.bagdia@arm.com * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
359793Sakash.bagdia@arm.com * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
369793Sakash.bagdia@arm.com * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
379793Sakash.bagdia@arm.com *
389793Sakash.bagdia@arm.com * Authors: Vasileios Spiliopoulos
399793Sakash.bagdia@arm.com *          Akash Bagdia
409793Sakash.bagdia@arm.com *          Andreas Hansson
4110000Sclt67@cornell.edu *          Christopher Torng
4210249Sstephan.diestelhorst@arm.com *          Stephan Diestelhorst
439793Sakash.bagdia@arm.com */
449793Sakash.bagdia@arm.com
4511793Sbrandon.potter@amd.com#include "sim/clock_domain.hh"
4611793Sbrandon.potter@amd.com
4710249Sstephan.diestelhorst@arm.com#include <algorithm>
4810249Sstephan.diestelhorst@arm.com#include <functional>
4910249Sstephan.diestelhorst@arm.com
5011800Sbrandon.potter@amd.com#include "base/trace.hh"
519793Sakash.bagdia@arm.com#include "debug/ClockDomain.hh"
529793Sakash.bagdia@arm.com#include "params/ClockDomain.hh"
539793Sakash.bagdia@arm.com#include "params/DerivedClockDomain.hh"
549793Sakash.bagdia@arm.com#include "params/SrcClockDomain.hh"
5511793Sbrandon.potter@amd.com#include "sim/clocked_object.hh"
569827Sakash.bagdia@arm.com#include "sim/voltage_domain.hh"
579793Sakash.bagdia@arm.com
5810021Sandreas.hansson@arm.comvoid
5910021Sandreas.hansson@arm.comClockDomain::regStats()
6010021Sandreas.hansson@arm.com{
6111523Sdavid.guillen@arm.com    SimObject::regStats();
6211523Sdavid.guillen@arm.com
6310021Sandreas.hansson@arm.com    using namespace Stats;
6410021Sandreas.hansson@arm.com
6510021Sandreas.hansson@arm.com    // Expose the current clock period as a stat for observability in
6610021Sandreas.hansson@arm.com    // the dumps
6710021Sandreas.hansson@arm.com    currentClock
6810021Sandreas.hansson@arm.com        .scalar(_clockPeriod)
6910021Sandreas.hansson@arm.com        .name(params()->name + ".clock")
7010021Sandreas.hansson@arm.com        .desc("Clock period in ticks")
7110021Sandreas.hansson@arm.com        ;
7210021Sandreas.hansson@arm.com}
7310021Sandreas.hansson@arm.com
749827Sakash.bagdia@arm.comdouble
759827Sakash.bagdia@arm.comClockDomain::voltage() const
769827Sakash.bagdia@arm.com{
779827Sakash.bagdia@arm.com    return _voltageDomain->voltage();
789827Sakash.bagdia@arm.com}
799827Sakash.bagdia@arm.com
809827Sakash.bagdia@arm.comSrcClockDomain::SrcClockDomain(const Params *p) :
8110249Sstephan.diestelhorst@arm.com    ClockDomain(p, p->voltage_domain),
8210249Sstephan.diestelhorst@arm.com    freqOpPoints(p->clock),
8310249Sstephan.diestelhorst@arm.com    _domainID(p->domain_id),
8410249Sstephan.diestelhorst@arm.com    _perfLevel(p->init_perf_level)
859793Sakash.bagdia@arm.com{
8610249Sstephan.diestelhorst@arm.com    VoltageDomain *vdom = p->voltage_domain;
8710249Sstephan.diestelhorst@arm.com
8810249Sstephan.diestelhorst@arm.com    fatal_if(freqOpPoints.empty(), "DVFS: Empty set of frequencies for "\
8910249Sstephan.diestelhorst@arm.com             "domain %d %s\n", _domainID, name());
9010249Sstephan.diestelhorst@arm.com
9110249Sstephan.diestelhorst@arm.com    fatal_if(!vdom, "DVFS: Empty voltage domain specified for "\
9210249Sstephan.diestelhorst@arm.com             "domain %d %s\n", _domainID, name());
9310249Sstephan.diestelhorst@arm.com
9410249Sstephan.diestelhorst@arm.com    fatal_if((vdom->numVoltages() > 1) &&
9510249Sstephan.diestelhorst@arm.com             (vdom->numVoltages() != freqOpPoints.size()),
9610249Sstephan.diestelhorst@arm.com             "DVFS: Number of frequency and voltage scaling points do "\
9710249Sstephan.diestelhorst@arm.com             "not match: %d:%d ID: %d %s.\n", vdom->numVoltages(),
9810249Sstephan.diestelhorst@arm.com             freqOpPoints.size(), _domainID, name());
9910249Sstephan.diestelhorst@arm.com
10010249Sstephan.diestelhorst@arm.com    // Frequency (& voltage) points should be declared in descending order,
10110249Sstephan.diestelhorst@arm.com    // NOTE: Frequency is inverted to ticks, so checking for ascending ticks
10210249Sstephan.diestelhorst@arm.com    fatal_if(!std::is_sorted(freqOpPoints.begin(), freqOpPoints.end()),
10310249Sstephan.diestelhorst@arm.com             "DVFS: Frequency operation points not in descending order for "\
10410249Sstephan.diestelhorst@arm.com             "domain with ID %d\n", _domainID);
10510249Sstephan.diestelhorst@arm.com
10610249Sstephan.diestelhorst@arm.com    fatal_if(_perfLevel >= freqOpPoints.size(), "DVFS: Initial DVFS point %d "\
10710249Sstephan.diestelhorst@arm.com             "is outside of list for Domain ID: %d\n", _perfLevel, _domainID);
10810249Sstephan.diestelhorst@arm.com
10910249Sstephan.diestelhorst@arm.com    clockPeriod(freqOpPoints[_perfLevel]);
11010249Sstephan.diestelhorst@arm.com
11110249Sstephan.diestelhorst@arm.com    vdom->registerSrcClockDom(this);
1129793Sakash.bagdia@arm.com}
1139793Sakash.bagdia@arm.com
1149793Sakash.bagdia@arm.comvoid
1159793Sakash.bagdia@arm.comSrcClockDomain::clockPeriod(Tick clock_period)
1169793Sakash.bagdia@arm.com{
1179793Sakash.bagdia@arm.com    if (clock_period == 0) {
1189793Sakash.bagdia@arm.com        fatal("%s has a clock period of zero\n", name());
1199793Sakash.bagdia@arm.com    }
1209793Sakash.bagdia@arm.com
12110000Sclt67@cornell.edu    // Align all members to the current tick
12210000Sclt67@cornell.edu    for (auto m = members.begin(); m != members.end(); ++m) {
12310000Sclt67@cornell.edu        (*m)->updateClockPeriod();
12410000Sclt67@cornell.edu    }
12510000Sclt67@cornell.edu
1269793Sakash.bagdia@arm.com    _clockPeriod = clock_period;
1279793Sakash.bagdia@arm.com
1289793Sakash.bagdia@arm.com    DPRINTF(ClockDomain,
1299793Sakash.bagdia@arm.com            "Setting clock period to %d ticks for source clock %s\n",
1309793Sakash.bagdia@arm.com            _clockPeriod, name());
1319793Sakash.bagdia@arm.com
1329793Sakash.bagdia@arm.com    // inform any derived clocks they need to updated their period
1339793Sakash.bagdia@arm.com    for (auto c = children.begin(); c != children.end(); ++c) {
1349793Sakash.bagdia@arm.com        (*c)->updateClockPeriod();
1359793Sakash.bagdia@arm.com    }
1369793Sakash.bagdia@arm.com}
1379793Sakash.bagdia@arm.com
13810249Sstephan.diestelhorst@arm.comvoid
13910249Sstephan.diestelhorst@arm.comSrcClockDomain::perfLevel(PerfLevel perf_level)
14010249Sstephan.diestelhorst@arm.com{
14110249Sstephan.diestelhorst@arm.com    assert(validPerfLevel(perf_level));
14210249Sstephan.diestelhorst@arm.com
14310395Sstephan.diestelhorst@arm.com    if (perf_level == _perfLevel) {
14410395Sstephan.diestelhorst@arm.com        // Silently ignore identical overwrites
14510395Sstephan.diestelhorst@arm.com        return;
14610395Sstephan.diestelhorst@arm.com    }
14710395Sstephan.diestelhorst@arm.com
14810249Sstephan.diestelhorst@arm.com    DPRINTF(ClockDomain, "DVFS: Switching performance level of domain %s "\
14910249Sstephan.diestelhorst@arm.com            "(id: %d) from  %d to %d\n", name(), domainID(), _perfLevel,
15010249Sstephan.diestelhorst@arm.com            perf_level);
15110249Sstephan.diestelhorst@arm.com
15210249Sstephan.diestelhorst@arm.com    _perfLevel = perf_level;
15310249Sstephan.diestelhorst@arm.com
15411416Ssascha.bischoff@ARM.com    signalPerfLevelUpdate();
15511416Ssascha.bischoff@ARM.com}
15611416Ssascha.bischoff@ARM.com
15711416Ssascha.bischoff@ARM.comvoid SrcClockDomain::signalPerfLevelUpdate()
15811416Ssascha.bischoff@ARM.com{
15910249Sstephan.diestelhorst@arm.com    // Signal the voltage domain that we have changed our perf level so that the
16010249Sstephan.diestelhorst@arm.com    // voltage domain can recompute its performance level
16110249Sstephan.diestelhorst@arm.com    voltageDomain()->sanitiseVoltages();
16210249Sstephan.diestelhorst@arm.com
16310249Sstephan.diestelhorst@arm.com    // Integrated switching of the actual clock value, too
16410249Sstephan.diestelhorst@arm.com    clockPeriod(clkPeriodAtPerfLevel());
16510249Sstephan.diestelhorst@arm.com}
16610249Sstephan.diestelhorst@arm.com
16710249Sstephan.diestelhorst@arm.comvoid
16810905Sandreas.sandberg@arm.comSrcClockDomain::serialize(CheckpointOut &cp) const
16910249Sstephan.diestelhorst@arm.com{
17010249Sstephan.diestelhorst@arm.com    SERIALIZE_SCALAR(_perfLevel);
17110905Sandreas.sandberg@arm.com    ClockDomain::serialize(cp);
17210249Sstephan.diestelhorst@arm.com}
17310249Sstephan.diestelhorst@arm.com
17410249Sstephan.diestelhorst@arm.comvoid
17510905Sandreas.sandberg@arm.comSrcClockDomain::unserialize(CheckpointIn &cp)
17610249Sstephan.diestelhorst@arm.com{
17710905Sandreas.sandberg@arm.com    ClockDomain::unserialize(cp);
17810249Sstephan.diestelhorst@arm.com    UNSERIALIZE_SCALAR(_perfLevel);
17910395Sstephan.diestelhorst@arm.com}
18010395Sstephan.diestelhorst@arm.com
18110395Sstephan.diestelhorst@arm.comvoid
18210395Sstephan.diestelhorst@arm.comSrcClockDomain::startup()
18310395Sstephan.diestelhorst@arm.com{
18410395Sstephan.diestelhorst@arm.com    // Perform proper clock update when all related components have been
18510395Sstephan.diestelhorst@arm.com    // created (i.e. after unserialization / object creation)
18611416Ssascha.bischoff@ARM.com    signalPerfLevelUpdate();
18710249Sstephan.diestelhorst@arm.com}
18810249Sstephan.diestelhorst@arm.com
1899793Sakash.bagdia@arm.comSrcClockDomain *
1909793Sakash.bagdia@arm.comSrcClockDomainParams::create()
1919793Sakash.bagdia@arm.com{
1929793Sakash.bagdia@arm.com    return new SrcClockDomain(this);
1939793Sakash.bagdia@arm.com}
1949793Sakash.bagdia@arm.com
1959793Sakash.bagdia@arm.comDerivedClockDomain::DerivedClockDomain(const Params *p) :
1969827Sakash.bagdia@arm.com    ClockDomain(p, p->clk_domain->voltageDomain()),
1979793Sakash.bagdia@arm.com    parent(*p->clk_domain),
1989793Sakash.bagdia@arm.com    clockDivider(p->clk_divider)
1999793Sakash.bagdia@arm.com{
2009793Sakash.bagdia@arm.com    // Ensure that clock divider setting works as frequency divider and never
2019793Sakash.bagdia@arm.com    // work as frequency multiplier
2029793Sakash.bagdia@arm.com    if (clockDivider < 1) {
2039793Sakash.bagdia@arm.com       fatal("Clock divider param cannot be less than 1");
2049793Sakash.bagdia@arm.com    }
2059793Sakash.bagdia@arm.com
2069793Sakash.bagdia@arm.com    // let the parent keep track of this derived domain so that it can
2079793Sakash.bagdia@arm.com    // propagate changes
2089793Sakash.bagdia@arm.com    parent.addDerivedDomain(this);
2099793Sakash.bagdia@arm.com
2109793Sakash.bagdia@arm.com    // update our clock period based on the parents clock
2119793Sakash.bagdia@arm.com    updateClockPeriod();
2129793Sakash.bagdia@arm.com}
2139793Sakash.bagdia@arm.com
2149793Sakash.bagdia@arm.comvoid
2159793Sakash.bagdia@arm.comDerivedClockDomain::updateClockPeriod()
2169793Sakash.bagdia@arm.com{
21710000Sclt67@cornell.edu    // Align all members to the current tick
21810000Sclt67@cornell.edu    for (auto m = members.begin(); m != members.end(); ++m) {
21910000Sclt67@cornell.edu        (*m)->updateClockPeriod();
22010000Sclt67@cornell.edu    }
22110000Sclt67@cornell.edu
2229793Sakash.bagdia@arm.com    // recalculate the clock period, relying on the fact that changes
2239793Sakash.bagdia@arm.com    // propagate downwards in the tree
2249793Sakash.bagdia@arm.com    _clockPeriod = parent.clockPeriod() * clockDivider;
2259793Sakash.bagdia@arm.com
2269793Sakash.bagdia@arm.com    DPRINTF(ClockDomain,
2279793Sakash.bagdia@arm.com            "Setting clock period to %d ticks for derived clock %s\n",
2289793Sakash.bagdia@arm.com            _clockPeriod, name());
2299793Sakash.bagdia@arm.com
2309793Sakash.bagdia@arm.com    // inform any derived clocks
2319793Sakash.bagdia@arm.com    for (auto c = children.begin(); c != children.end(); ++c) {
2329793Sakash.bagdia@arm.com        (*c)->updateClockPeriod();
2339793Sakash.bagdia@arm.com    }
2349793Sakash.bagdia@arm.com}
2359793Sakash.bagdia@arm.com
2369793Sakash.bagdia@arm.comDerivedClockDomain *
2379793Sakash.bagdia@arm.comDerivedClockDomainParams::create()
2389793Sakash.bagdia@arm.com{
2399793Sakash.bagdia@arm.com    return new DerivedClockDomain(this);
2409793Sakash.bagdia@arm.com}
241