intel_8254_timer.cc revision 10905
15443Sgblack@eecs.umich.edu/* 25443Sgblack@eecs.umich.edu * Copyright (c) 2004, 2005 35443Sgblack@eecs.umich.edu * The Regents of The University of Michigan 45443Sgblack@eecs.umich.edu * All Rights Reserved 55443Sgblack@eecs.umich.edu * 65443Sgblack@eecs.umich.edu * This code is part of the M5 simulator. 75443Sgblack@eecs.umich.edu * 85443Sgblack@eecs.umich.edu * Permission is granted to use, copy, create derivative works and 95443Sgblack@eecs.umich.edu * redistribute this software and such derivative works for any 105443Sgblack@eecs.umich.edu * purpose, so long as the copyright notice above, this grant of 115443Sgblack@eecs.umich.edu * permission, and the disclaimer below appear in all copies made; and 125443Sgblack@eecs.umich.edu * so long as the name of The University of Michigan is not used in 135443Sgblack@eecs.umich.edu * any advertising or publicity pertaining to the use or distribution 145443Sgblack@eecs.umich.edu * of this software without specific, written prior authorization. 155443Sgblack@eecs.umich.edu * 165443Sgblack@eecs.umich.edu * THIS SOFTWARE IS PROVIDED AS IS, WITHOUT REPRESENTATION FROM THE 175443Sgblack@eecs.umich.edu * UNIVERSITY OF MICHIGAN AS TO ITS FITNESS FOR ANY PURPOSE, AND 185443Sgblack@eecs.umich.edu * WITHOUT WARRANTY BY THE UNIVERSITY OF MICHIGAN OF ANY KIND, EITHER 195443Sgblack@eecs.umich.edu * EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED 205443Sgblack@eecs.umich.edu * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 215443Sgblack@eecs.umich.edu * PURPOSE. THE REGENTS OF THE UNIVERSITY OF MICHIGAN SHALL NOT BE 225443Sgblack@eecs.umich.edu * LIABLE FOR ANY DAMAGES, INCLUDING DIRECT, SPECIAL, INDIRECT, 235443Sgblack@eecs.umich.edu * INCIDENTAL, OR CONSEQUENTIAL DAMAGES, WITH RESPECT TO ANY CLAIM 245443Sgblack@eecs.umich.edu * ARISING OUT OF OR IN CONNECTION WITH THE USE OF THE SOFTWARE, EVEN 255443Sgblack@eecs.umich.edu * IF IT HAS BEEN OR IS HEREAFTER ADVISED OF THE POSSIBILITY OF SUCH 265443Sgblack@eecs.umich.edu * DAMAGES. 275443Sgblack@eecs.umich.edu * 285443Sgblack@eecs.umich.edu * Authors: Ali G. Saidi 295443Sgblack@eecs.umich.edu * Andrew L. Schultz 305443Sgblack@eecs.umich.edu * Miguel J. Serrano 315443Sgblack@eecs.umich.edu */ 325443Sgblack@eecs.umich.edu 335443Sgblack@eecs.umich.edu#include "base/misc.hh" 348232Snate@binkert.org#include "debug/Intel8254Timer.hh" 355443Sgblack@eecs.umich.edu#include "dev/intel_8254_timer.hh" 365443Sgblack@eecs.umich.edu 375443Sgblack@eecs.umich.eduusing namespace std; 385443Sgblack@eecs.umich.edu 395635Sgblack@eecs.umich.eduIntel8254Timer::Intel8254Timer(EventManager *em, const string &name, 405635Sgblack@eecs.umich.edu Counter *counter0, Counter *counter1, Counter *counter2) : 415635Sgblack@eecs.umich.edu EventManager(em), _name(name) 425443Sgblack@eecs.umich.edu{ 435635Sgblack@eecs.umich.edu counter[0] = counter0; 445635Sgblack@eecs.umich.edu counter[1] = counter1; 455635Sgblack@eecs.umich.edu counter[2] = counter2; 465635Sgblack@eecs.umich.edu} 475635Sgblack@eecs.umich.edu 485635Sgblack@eecs.umich.eduIntel8254Timer::Intel8254Timer(EventManager *em, const string &name) : 495635Sgblack@eecs.umich.edu EventManager(em), _name(name) 505635Sgblack@eecs.umich.edu{ 515642Sgblack@eecs.umich.edu counter[0] = new Counter(this, name + ".counter0", 0); 525642Sgblack@eecs.umich.edu counter[1] = new Counter(this, name + ".counter1", 1); 535642Sgblack@eecs.umich.edu counter[2] = new Counter(this, name + ".counter2", 2); 545443Sgblack@eecs.umich.edu} 555443Sgblack@eecs.umich.edu 565443Sgblack@eecs.umich.eduvoid 575443Sgblack@eecs.umich.eduIntel8254Timer::writeControl(const CtrlReg data) 585443Sgblack@eecs.umich.edu{ 595443Sgblack@eecs.umich.edu int sel = data.sel; 605443Sgblack@eecs.umich.edu 615443Sgblack@eecs.umich.edu if (sel == ReadBackCommand) 625443Sgblack@eecs.umich.edu panic("PITimer Read-Back Command is not implemented.\n"); 635443Sgblack@eecs.umich.edu 645443Sgblack@eecs.umich.edu if (data.rw == LatchCommand) 655443Sgblack@eecs.umich.edu counter[sel]->latchCount(); 665443Sgblack@eecs.umich.edu else { 675443Sgblack@eecs.umich.edu counter[sel]->setRW(data.rw); 685443Sgblack@eecs.umich.edu counter[sel]->setMode(data.mode); 695443Sgblack@eecs.umich.edu counter[sel]->setBCD(data.bcd); 705443Sgblack@eecs.umich.edu } 715443Sgblack@eecs.umich.edu} 725443Sgblack@eecs.umich.edu 735443Sgblack@eecs.umich.eduvoid 7410905Sandreas.sandberg@arm.comIntel8254Timer::serialize(const string &base, CheckpointOut &cp) const 755443Sgblack@eecs.umich.edu{ 765443Sgblack@eecs.umich.edu // serialize the counters 7710905Sandreas.sandberg@arm.com counter[0]->serialize(base + ".counter0", cp); 7810905Sandreas.sandberg@arm.com counter[1]->serialize(base + ".counter1", cp); 7910905Sandreas.sandberg@arm.com counter[2]->serialize(base + ".counter2", cp); 805443Sgblack@eecs.umich.edu} 815443Sgblack@eecs.umich.edu 825443Sgblack@eecs.umich.eduvoid 8310905Sandreas.sandberg@arm.comIntel8254Timer::unserialize(const string &base, CheckpointIn &cp) 845443Sgblack@eecs.umich.edu{ 855443Sgblack@eecs.umich.edu // unserialze the counters 8610905Sandreas.sandberg@arm.com counter[0]->unserialize(base + ".counter0", cp); 8710905Sandreas.sandberg@arm.com counter[1]->unserialize(base + ".counter1", cp); 8810905Sandreas.sandberg@arm.com counter[2]->unserialize(base + ".counter2", cp); 895443Sgblack@eecs.umich.edu} 905443Sgblack@eecs.umich.edu 9110642Scdirik@micron.comvoid 9210642Scdirik@micron.comIntel8254Timer::startup() 9310642Scdirik@micron.com{ 9410642Scdirik@micron.com counter[0]->startup(); 9510642Scdirik@micron.com counter[1]->startup(); 9610642Scdirik@micron.com counter[2]->startup(); 9710642Scdirik@micron.com} 9810642Scdirik@micron.com 995642Sgblack@eecs.umich.eduIntel8254Timer::Counter::Counter(Intel8254Timer *p, 1005642Sgblack@eecs.umich.edu const string &name, unsigned int _num) 10110642Scdirik@micron.com : _name(name), num(_num), event(this), running(false), 10210642Scdirik@micron.com initial_count(0), latched_count(0), period(0), mode(0), 10310642Scdirik@micron.com output_high(false), latch_on(false), read_byte(LSB), 10410642Scdirik@micron.com write_byte(LSB), parent(p) 1055443Sgblack@eecs.umich.edu{ 10610642Scdirik@micron.com offset = period * event.getInterval(); 1075443Sgblack@eecs.umich.edu} 1085443Sgblack@eecs.umich.edu 1095443Sgblack@eecs.umich.eduvoid 1105443Sgblack@eecs.umich.eduIntel8254Timer::Counter::latchCount() 1115443Sgblack@eecs.umich.edu{ 1125443Sgblack@eecs.umich.edu // behave like a real latch 1135443Sgblack@eecs.umich.edu if(!latch_on) { 1145443Sgblack@eecs.umich.edu latch_on = true; 1155443Sgblack@eecs.umich.edu read_byte = LSB; 1166067Sgblack@eecs.umich.edu latched_count = currentCount(); 1175443Sgblack@eecs.umich.edu } 1185443Sgblack@eecs.umich.edu} 1195443Sgblack@eecs.umich.edu 1206067Sgblack@eecs.umich.eduint 1216067Sgblack@eecs.umich.eduIntel8254Timer::Counter::currentCount() 1226067Sgblack@eecs.umich.edu{ 1236067Sgblack@eecs.umich.edu int clocks = event.clocksLeft(); 1246067Sgblack@eecs.umich.edu if (clocks == -1) { 1256067Sgblack@eecs.umich.edu warn_once("Reading current count from inactive timer.\n"); 1266067Sgblack@eecs.umich.edu return 0; 1276067Sgblack@eecs.umich.edu } 1286067Sgblack@eecs.umich.edu if (mode == RateGen || mode == SquareWave) 1296067Sgblack@eecs.umich.edu return clocks + 1; 1306067Sgblack@eecs.umich.edu else 1316067Sgblack@eecs.umich.edu return clocks; 1326067Sgblack@eecs.umich.edu} 1336067Sgblack@eecs.umich.edu 1345443Sgblack@eecs.umich.eduuint8_t 1355443Sgblack@eecs.umich.eduIntel8254Timer::Counter::read() 1365443Sgblack@eecs.umich.edu{ 1375443Sgblack@eecs.umich.edu if (latch_on) { 1385443Sgblack@eecs.umich.edu switch (read_byte) { 1395443Sgblack@eecs.umich.edu case LSB: 1405443Sgblack@eecs.umich.edu read_byte = MSB; 1415443Sgblack@eecs.umich.edu return (uint8_t)latched_count; 1425443Sgblack@eecs.umich.edu break; 1435443Sgblack@eecs.umich.edu case MSB: 1445443Sgblack@eecs.umich.edu read_byte = LSB; 1455443Sgblack@eecs.umich.edu latch_on = false; 1465443Sgblack@eecs.umich.edu return latched_count >> 8; 1475443Sgblack@eecs.umich.edu break; 1485443Sgblack@eecs.umich.edu default: 1495443Sgblack@eecs.umich.edu panic("Shouldn't be here"); 1505443Sgblack@eecs.umich.edu } 1515443Sgblack@eecs.umich.edu } else { 1526067Sgblack@eecs.umich.edu uint16_t count = currentCount(); 1535443Sgblack@eecs.umich.edu switch (read_byte) { 1545443Sgblack@eecs.umich.edu case LSB: 1555443Sgblack@eecs.umich.edu read_byte = MSB; 1565443Sgblack@eecs.umich.edu return (uint8_t)count; 1575443Sgblack@eecs.umich.edu break; 1585443Sgblack@eecs.umich.edu case MSB: 1595443Sgblack@eecs.umich.edu read_byte = LSB; 1605443Sgblack@eecs.umich.edu return count >> 8; 1615443Sgblack@eecs.umich.edu break; 1625443Sgblack@eecs.umich.edu default: 1635443Sgblack@eecs.umich.edu panic("Shouldn't be here"); 1645443Sgblack@eecs.umich.edu } 1655443Sgblack@eecs.umich.edu } 1665443Sgblack@eecs.umich.edu} 1675443Sgblack@eecs.umich.edu 1685443Sgblack@eecs.umich.eduvoid 1695443Sgblack@eecs.umich.eduIntel8254Timer::Counter::write(const uint8_t data) 1705443Sgblack@eecs.umich.edu{ 1715443Sgblack@eecs.umich.edu switch (write_byte) { 1725443Sgblack@eecs.umich.edu case LSB: 1736067Sgblack@eecs.umich.edu initial_count = (initial_count & 0xFF00) | data; 1745443Sgblack@eecs.umich.edu 1755443Sgblack@eecs.umich.edu if (event.scheduled()) 1765606Snate@binkert.org parent->deschedule(event); 1775443Sgblack@eecs.umich.edu output_high = false; 1785443Sgblack@eecs.umich.edu write_byte = MSB; 1795443Sgblack@eecs.umich.edu break; 1805443Sgblack@eecs.umich.edu 1815443Sgblack@eecs.umich.edu case MSB: 1826067Sgblack@eecs.umich.edu initial_count = (initial_count & 0x00FF) | (data << 8); 1835444Sgblack@eecs.umich.edu // In the RateGen or SquareWave modes, the timer wraps around and 1845444Sgblack@eecs.umich.edu // triggers on a value of 1, not 0. 1855444Sgblack@eecs.umich.edu if (mode == RateGen || mode == SquareWave) 1866067Sgblack@eecs.umich.edu period = initial_count - 1; 1875444Sgblack@eecs.umich.edu else 1886067Sgblack@eecs.umich.edu period = initial_count; 1895443Sgblack@eecs.umich.edu 19010642Scdirik@micron.com offset = period * event.getInterval(); 19110642Scdirik@micron.com 19210642Scdirik@micron.com if (running && (period > 0)) 1935444Sgblack@eecs.umich.edu event.setTo(period); 1945444Sgblack@eecs.umich.edu 1955443Sgblack@eecs.umich.edu write_byte = LSB; 1965443Sgblack@eecs.umich.edu break; 1975443Sgblack@eecs.umich.edu } 1985443Sgblack@eecs.umich.edu} 1995443Sgblack@eecs.umich.edu 2005443Sgblack@eecs.umich.eduvoid 2015443Sgblack@eecs.umich.eduIntel8254Timer::Counter::setRW(int rw_val) 2025443Sgblack@eecs.umich.edu{ 2035443Sgblack@eecs.umich.edu if (rw_val != TwoPhase) 2045443Sgblack@eecs.umich.edu panic("Only LSB/MSB read/write is implemented.\n"); 2055443Sgblack@eecs.umich.edu} 2065443Sgblack@eecs.umich.edu 2075443Sgblack@eecs.umich.eduvoid 2085443Sgblack@eecs.umich.eduIntel8254Timer::Counter::setMode(int mode_val) 2095443Sgblack@eecs.umich.edu{ 2105443Sgblack@eecs.umich.edu if(mode_val != InitTc && mode_val != RateGen && 2115443Sgblack@eecs.umich.edu mode_val != SquareWave) 2125443Sgblack@eecs.umich.edu panic("PIT mode %#x is not implemented: \n", mode_val); 2135443Sgblack@eecs.umich.edu 2145443Sgblack@eecs.umich.edu mode = mode_val; 2155443Sgblack@eecs.umich.edu} 2165443Sgblack@eecs.umich.edu 2175443Sgblack@eecs.umich.eduvoid 2185443Sgblack@eecs.umich.eduIntel8254Timer::Counter::setBCD(int bcd_val) 2195443Sgblack@eecs.umich.edu{ 2205443Sgblack@eecs.umich.edu if (bcd_val) 2215443Sgblack@eecs.umich.edu panic("PITimer does not implement BCD counts.\n"); 2225443Sgblack@eecs.umich.edu} 2235443Sgblack@eecs.umich.edu 2245443Sgblack@eecs.umich.edubool 2255443Sgblack@eecs.umich.eduIntel8254Timer::Counter::outputHigh() 2265443Sgblack@eecs.umich.edu{ 2275443Sgblack@eecs.umich.edu return output_high; 2285443Sgblack@eecs.umich.edu} 2295443Sgblack@eecs.umich.edu 2305443Sgblack@eecs.umich.eduvoid 23110905Sandreas.sandberg@arm.comIntel8254Timer::Counter::serialize(const string &base, CheckpointOut &cp) const 2325443Sgblack@eecs.umich.edu{ 23310905Sandreas.sandberg@arm.com paramOut(cp, base + ".initial_count", initial_count); 23410905Sandreas.sandberg@arm.com paramOut(cp, base + ".latched_count", latched_count); 23510905Sandreas.sandberg@arm.com paramOut(cp, base + ".period", period); 23610905Sandreas.sandberg@arm.com paramOut(cp, base + ".mode", mode); 23710905Sandreas.sandberg@arm.com paramOut(cp, base + ".output_high", output_high); 23810905Sandreas.sandberg@arm.com paramOut(cp, base + ".latch_on", latch_on); 23910905Sandreas.sandberg@arm.com paramOut(cp, base + ".read_byte", read_byte); 24010905Sandreas.sandberg@arm.com paramOut(cp, base + ".write_byte", write_byte); 2417683Ssteve.reinhardt@amd.com 24210642Scdirik@micron.com Tick event_tick_offset = 0; 2437683Ssteve.reinhardt@amd.com if (event.scheduled()) 24410642Scdirik@micron.com event_tick_offset = event.when() - curTick(); 24510905Sandreas.sandberg@arm.com paramOut(cp, base + ".event_tick_offset", event_tick_offset); 2465443Sgblack@eecs.umich.edu} 2475443Sgblack@eecs.umich.edu 2485443Sgblack@eecs.umich.eduvoid 24910905Sandreas.sandberg@arm.comIntel8254Timer::Counter::unserialize(const string &base, CheckpointIn &cp) 2505443Sgblack@eecs.umich.edu{ 25110905Sandreas.sandberg@arm.com paramIn(cp, base + ".initial_count", initial_count); 25210905Sandreas.sandberg@arm.com paramIn(cp, base + ".latched_count", latched_count); 25310905Sandreas.sandberg@arm.com paramIn(cp, base + ".period", period); 25410905Sandreas.sandberg@arm.com paramIn(cp, base + ".mode", mode); 25510905Sandreas.sandberg@arm.com paramIn(cp, base + ".output_high", output_high); 25610905Sandreas.sandberg@arm.com paramIn(cp, base + ".latch_on", latch_on); 25710905Sandreas.sandberg@arm.com paramIn(cp, base + ".read_byte", read_byte); 25810905Sandreas.sandberg@arm.com paramIn(cp, base + ".write_byte", write_byte); 2595443Sgblack@eecs.umich.edu 26010642Scdirik@micron.com Tick event_tick_offset = 0; 26110642Scdirik@micron.com assert(!event.scheduled()); 26210905Sandreas.sandberg@arm.com paramIn(cp, base + ".event_tick_offset", event_tick_offset); 26310642Scdirik@micron.com offset = event_tick_offset; 26410642Scdirik@micron.com} 26510642Scdirik@micron.com 26610642Scdirik@micron.comvoid 26710642Scdirik@micron.comIntel8254Timer::Counter::startup() 26810642Scdirik@micron.com{ 26910642Scdirik@micron.com running = true; 27010642Scdirik@micron.com if ((period > 0) && (offset > 0)) 27110642Scdirik@micron.com { 27210642Scdirik@micron.com parent->schedule(event, curTick() + offset); 27310642Scdirik@micron.com } 2745443Sgblack@eecs.umich.edu} 2755443Sgblack@eecs.umich.edu 2765443Sgblack@eecs.umich.eduIntel8254Timer::Counter::CounterEvent::CounterEvent(Counter* c_ptr) 2775443Sgblack@eecs.umich.edu{ 2787064Snate@binkert.org interval = (Tick)(SimClock::Float::s / 1193180.0); 2795443Sgblack@eecs.umich.edu counter = c_ptr; 2805443Sgblack@eecs.umich.edu} 2815443Sgblack@eecs.umich.edu 2825443Sgblack@eecs.umich.eduvoid 2835443Sgblack@eecs.umich.eduIntel8254Timer::Counter::CounterEvent::process() 2845443Sgblack@eecs.umich.edu{ 2855443Sgblack@eecs.umich.edu switch (counter->mode) { 2865443Sgblack@eecs.umich.edu case InitTc: 2875443Sgblack@eecs.umich.edu counter->output_high = true; 2885444Sgblack@eecs.umich.edu break; 2895443Sgblack@eecs.umich.edu case RateGen: 2905443Sgblack@eecs.umich.edu case SquareWave: 2915444Sgblack@eecs.umich.edu setTo(counter->period); 2925443Sgblack@eecs.umich.edu break; 2935443Sgblack@eecs.umich.edu default: 2945443Sgblack@eecs.umich.edu panic("Unimplemented PITimer mode.\n"); 2955443Sgblack@eecs.umich.edu } 2965642Sgblack@eecs.umich.edu counter->parent->counterInterrupt(counter->num); 2975443Sgblack@eecs.umich.edu} 2985443Sgblack@eecs.umich.edu 2995444Sgblack@eecs.umich.eduvoid 3005444Sgblack@eecs.umich.eduIntel8254Timer::Counter::CounterEvent::setTo(int clocks) 3015444Sgblack@eecs.umich.edu{ 3025444Sgblack@eecs.umich.edu if (clocks == 0) 3035444Sgblack@eecs.umich.edu panic("Timer can't be set to go off instantly.\n"); 3047823Ssteve.reinhardt@amd.com DPRINTF(Intel8254Timer, "Timer set to curTick() + %d\n", 3055444Sgblack@eecs.umich.edu clocks * interval); 3067823Ssteve.reinhardt@amd.com counter->parent->schedule(this, curTick() + clocks * interval); 3075444Sgblack@eecs.umich.edu} 3085444Sgblack@eecs.umich.edu 3096067Sgblack@eecs.umich.eduint 3106067Sgblack@eecs.umich.eduIntel8254Timer::Counter::CounterEvent::clocksLeft() 3116067Sgblack@eecs.umich.edu{ 3126067Sgblack@eecs.umich.edu if (!scheduled()) 3136067Sgblack@eecs.umich.edu return -1; 3147823Ssteve.reinhardt@amd.com return (when() - curTick() + interval - 1) / interval; 3156067Sgblack@eecs.umich.edu} 3166067Sgblack@eecs.umich.edu 3175443Sgblack@eecs.umich.educonst char * 3185443Sgblack@eecs.umich.eduIntel8254Timer::Counter::CounterEvent::description() const 3195443Sgblack@eecs.umich.edu{ 3205642Sgblack@eecs.umich.edu return "Intel 8254 Interval timer"; 3215443Sgblack@eecs.umich.edu} 32210642Scdirik@micron.com 32310642Scdirik@micron.comTick 32410642Scdirik@micron.comIntel8254Timer::Counter::CounterEvent::getInterval() 32510642Scdirik@micron.com{ 32610642Scdirik@micron.com return interval; 32710642Scdirik@micron.com} 32810642Scdirik@micron.com 329