generic_timer.cc revision 10037
1/* 2 * Copyright (c) 2013 ARM Limited 3 * All rights reserved. 4 * 5 * The license below extends only to copyright in the software and shall 6 * not be construed as granting a license to any other intellectual 7 * property including but not limited to intellectual property relating 8 * to a hardware implementation of the functionality of the software 9 * licensed hereunder. You may use the software subject to the license 10 * terms below provided that you ensure that this notice is replicated 11 * unmodified and in its entirety in all distributions of the software, 12 * modified or unmodified, in source code or in binary form. 13 * 14 * Redistribution and use in source and binary forms, with or without 15 * modification, are permitted provided that the following conditions are 16 * met: redistributions of source code must retain the above copyright 17 * notice, this list of conditions and the following disclaimer; 18 * redistributions in binary form must reproduce the above copyright 19 * notice, this list of conditions and the following disclaimer in the 20 * documentation and/or other materials provided with the distribution; 21 * neither the name of the copyright holders nor the names of its 22 * contributors may be used to endorse or promote products derived from 23 * this software without specific prior written permission. 24 * 25 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 26 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 27 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 28 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 29 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 30 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 31 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 32 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 33 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 34 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 35 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 36 * 37 * Authors: Giacomo Gabrielli 38 */ 39 40#include "arch/arm/system.hh" 41#include "debug/Checkpoint.hh" 42#include "debug/Timer.hh" 43#include "dev/arm/base_gic.hh" 44#include "dev/arm/generic_timer.hh" 45 46void 47GenericTimer::SystemCounter::setFreq(uint32_t freq) 48{ 49 if (_freq != 0) { 50 // Altering the frequency after boot shouldn't be done in practice. 51 warn_once("The frequency of the system counter has already been set"); 52 } 53 _freq = freq; 54 _period = (1.0 / freq) * SimClock::Frequency; 55 _resetTick = curTick(); 56} 57 58void 59GenericTimer::SystemCounter::serialize(std::ostream &os) 60{ 61 SERIALIZE_SCALAR(_freq); 62 SERIALIZE_SCALAR(_period); 63 SERIALIZE_SCALAR(_resetTick); 64} 65 66void 67GenericTimer::SystemCounter::unserialize(Checkpoint *cp, 68 const std::string §ion) 69{ 70 UNSERIALIZE_SCALAR(_freq); 71 UNSERIALIZE_SCALAR(_period); 72 UNSERIALIZE_SCALAR(_resetTick); 73} 74 75void 76GenericTimer::ArchTimer::counterLimitReached() 77{ 78 _control.istatus = 1; 79 80 if (!_control.enable) 81 return; 82 83 // DPRINTF(Timer, "Counter limit reached\n"); 84 85 if (!_control.imask) { 86 // DPRINTF(Timer, "Causing interrupt\n"); 87 _parent->_gic->sendPPInt(_intNum, _cpuNum); 88 } 89} 90 91void 92GenericTimer::ArchTimer::setCompareValue(uint64_t val) 93{ 94 _counterLimit = val; 95 if (_counterLimitReachedEvent.scheduled()) 96 _parent->deschedule(_counterLimitReachedEvent); 97 if (counterValue() >= _counterLimit) { 98 counterLimitReached(); 99 } else { 100 _control.istatus = 0; 101 _parent->schedule(_counterLimitReachedEvent, 102 curTick() + (_counterLimit - counterValue()) * _counter->period()); 103 } 104} 105 106void 107GenericTimer::ArchTimer::setTimerValue(uint32_t val) 108{ 109 setCompareValue(counterValue() + sext<32>(val)); 110} 111 112void 113GenericTimer::ArchTimer::setControl(uint32_t val) 114{ 115 ArchTimerCtrl new_ctl = val; 116 if ((new_ctl.enable && !new_ctl.imask) && 117 !(_control.enable && !_control.imask)) { 118 // Re-evalute the timer condition 119 if (_counterLimit >= counterValue()) { 120 _control.istatus = 1; 121 122 DPRINTF(Timer, "Causing interrupt in control\n"); 123 //_parent->_gic->sendPPInt(_intNum, _cpuNum); 124 } 125 } 126 _control.enable = new_ctl.enable; 127 _control.imask = new_ctl.imask; 128} 129 130void 131GenericTimer::ArchTimer::serialize(std::ostream &os) 132{ 133 SERIALIZE_SCALAR(_cpuNum); 134 SERIALIZE_SCALAR(_intNum); 135 uint32_t control_serial = _control; 136 SERIALIZE_SCALAR(control_serial); 137 SERIALIZE_SCALAR(_counterLimit); 138 bool event_scheduled = _counterLimitReachedEvent.scheduled(); 139 SERIALIZE_SCALAR(event_scheduled); 140 Tick event_time; 141 if (event_scheduled) { 142 event_time = _counterLimitReachedEvent.when(); 143 SERIALIZE_SCALAR(event_time); 144 } 145} 146 147void 148GenericTimer::ArchTimer::unserialize(Checkpoint *cp, const std::string §ion) 149{ 150 UNSERIALIZE_SCALAR(_cpuNum); 151 UNSERIALIZE_SCALAR(_intNum); 152 uint32_t control_serial; 153 UNSERIALIZE_SCALAR(control_serial); 154 _control = control_serial; 155 bool event_scheduled; 156 UNSERIALIZE_SCALAR(event_scheduled); 157 Tick event_time; 158 if (event_scheduled) { 159 UNSERIALIZE_SCALAR(event_time); 160 _parent->schedule(_counterLimitReachedEvent, event_time); 161 } 162} 163 164GenericTimer::GenericTimer(Params *p) 165 : SimObject(p), _gic(p->gic) 166{ 167 for (int i = 0; i < CPU_MAX; ++i) { 168 std::stringstream oss; 169 oss << name() << ".arch_timer" << i; 170 _archTimers[i]._name = oss.str(); 171 _archTimers[i]._parent = this; 172 _archTimers[i]._counter = &_systemCounter; 173 _archTimers[i]._cpuNum = i; 174 _archTimers[i]._intNum = p->int_num; 175 } 176 177 ((ArmSystem *) p->system)->setGenericTimer(this); 178} 179 180void 181GenericTimer::serialize(std::ostream &os) 182{ 183 nameOut(os, csprintf("%s.sys_counter", name())); 184 _systemCounter.serialize(os); 185 for (int i = 0; i < CPU_MAX; ++i) { 186 nameOut(os, csprintf("%s.arch_timer%d", name(), i)); 187 _archTimers[i].serialize(os); 188 } 189} 190 191void 192GenericTimer::unserialize(Checkpoint *cp, const std::string §ion) 193{ 194 _systemCounter.unserialize(cp, csprintf("%s.sys_counter", section)); 195 for (int i = 0; i < CPU_MAX; ++i) { 196 _archTimers[i].unserialize(cp, csprintf("%s.arch_timer%d", section, i)); 197 } 198} 199 200GenericTimer * 201GenericTimerParams::create() 202{ 203 return new GenericTimer(this); 204} 205