intel_8254_timer.cc revision 5635
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" 345443Sgblack@eecs.umich.edu#include "dev/intel_8254_timer.hh" 355443Sgblack@eecs.umich.edu 365443Sgblack@eecs.umich.eduusing namespace std; 375443Sgblack@eecs.umich.edu 385635Sgblack@eecs.umich.eduIntel8254Timer::Intel8254Timer(EventManager *em, const string &name, 395635Sgblack@eecs.umich.edu Counter *counter0, Counter *counter1, Counter *counter2) : 405635Sgblack@eecs.umich.edu EventManager(em), _name(name) 415443Sgblack@eecs.umich.edu{ 425635Sgblack@eecs.umich.edu counter[0] = counter0; 435635Sgblack@eecs.umich.edu counter[1] = counter1; 445635Sgblack@eecs.umich.edu counter[2] = counter2; 455635Sgblack@eecs.umich.edu} 465635Sgblack@eecs.umich.edu 475635Sgblack@eecs.umich.eduIntel8254Timer::Intel8254Timer(EventManager *em, const string &name) : 485635Sgblack@eecs.umich.edu EventManager(em), _name(name) 495635Sgblack@eecs.umich.edu{ 505635Sgblack@eecs.umich.edu counter[0] = new Counter(this, name + ".counter0"); 515635Sgblack@eecs.umich.edu counter[1] = new Counter(this, name + ".counter1"); 525635Sgblack@eecs.umich.edu counter[2] = new Counter(this, name + ".counter2"); 535443Sgblack@eecs.umich.edu} 545443Sgblack@eecs.umich.edu 555443Sgblack@eecs.umich.eduvoid 565443Sgblack@eecs.umich.eduIntel8254Timer::writeControl(const CtrlReg data) 575443Sgblack@eecs.umich.edu{ 585443Sgblack@eecs.umich.edu int sel = data.sel; 595443Sgblack@eecs.umich.edu 605443Sgblack@eecs.umich.edu if (sel == ReadBackCommand) 615443Sgblack@eecs.umich.edu panic("PITimer Read-Back Command is not implemented.\n"); 625443Sgblack@eecs.umich.edu 635443Sgblack@eecs.umich.edu if (data.rw == LatchCommand) 645443Sgblack@eecs.umich.edu counter[sel]->latchCount(); 655443Sgblack@eecs.umich.edu else { 665443Sgblack@eecs.umich.edu counter[sel]->setRW(data.rw); 675443Sgblack@eecs.umich.edu counter[sel]->setMode(data.mode); 685443Sgblack@eecs.umich.edu counter[sel]->setBCD(data.bcd); 695443Sgblack@eecs.umich.edu } 705443Sgblack@eecs.umich.edu} 715443Sgblack@eecs.umich.edu 725443Sgblack@eecs.umich.eduvoid 735443Sgblack@eecs.umich.eduIntel8254Timer::serialize(const string &base, ostream &os) 745443Sgblack@eecs.umich.edu{ 755443Sgblack@eecs.umich.edu // serialize the counters 765635Sgblack@eecs.umich.edu counter[0]->serialize(base + ".counter0", os); 775635Sgblack@eecs.umich.edu counter[1]->serialize(base + ".counter1", os); 785635Sgblack@eecs.umich.edu counter[2]->serialize(base + ".counter2", os); 795443Sgblack@eecs.umich.edu} 805443Sgblack@eecs.umich.edu 815443Sgblack@eecs.umich.eduvoid 825443Sgblack@eecs.umich.eduIntel8254Timer::unserialize(const string &base, Checkpoint *cp, 835443Sgblack@eecs.umich.edu const string §ion) 845443Sgblack@eecs.umich.edu{ 855443Sgblack@eecs.umich.edu // unserialze the counters 865635Sgblack@eecs.umich.edu counter[0]->unserialize(base + ".counter0", cp, section); 875635Sgblack@eecs.umich.edu counter[1]->unserialize(base + ".counter1", cp, section); 885635Sgblack@eecs.umich.edu counter[2]->unserialize(base + ".counter2", cp, section); 895443Sgblack@eecs.umich.edu} 905443Sgblack@eecs.umich.edu 915606Snate@binkert.orgIntel8254Timer::Counter::Counter(Intel8254Timer *p, const string &name) 925443Sgblack@eecs.umich.edu : _name(name), event(this), count(0), latched_count(0), period(0), 935443Sgblack@eecs.umich.edu mode(0), output_high(false), latch_on(false), read_byte(LSB), 945606Snate@binkert.org write_byte(LSB), parent(p) 955443Sgblack@eecs.umich.edu{ 965443Sgblack@eecs.umich.edu 975443Sgblack@eecs.umich.edu} 985443Sgblack@eecs.umich.edu 995443Sgblack@eecs.umich.eduvoid 1005443Sgblack@eecs.umich.eduIntel8254Timer::Counter::latchCount() 1015443Sgblack@eecs.umich.edu{ 1025443Sgblack@eecs.umich.edu // behave like a real latch 1035443Sgblack@eecs.umich.edu if(!latch_on) { 1045443Sgblack@eecs.umich.edu latch_on = true; 1055443Sgblack@eecs.umich.edu read_byte = LSB; 1065443Sgblack@eecs.umich.edu latched_count = count; 1075443Sgblack@eecs.umich.edu } 1085443Sgblack@eecs.umich.edu} 1095443Sgblack@eecs.umich.edu 1105443Sgblack@eecs.umich.eduuint8_t 1115443Sgblack@eecs.umich.eduIntel8254Timer::Counter::read() 1125443Sgblack@eecs.umich.edu{ 1135443Sgblack@eecs.umich.edu if (latch_on) { 1145443Sgblack@eecs.umich.edu switch (read_byte) { 1155443Sgblack@eecs.umich.edu case LSB: 1165443Sgblack@eecs.umich.edu read_byte = MSB; 1175443Sgblack@eecs.umich.edu return (uint8_t)latched_count; 1185443Sgblack@eecs.umich.edu break; 1195443Sgblack@eecs.umich.edu case MSB: 1205443Sgblack@eecs.umich.edu read_byte = LSB; 1215443Sgblack@eecs.umich.edu latch_on = false; 1225443Sgblack@eecs.umich.edu return latched_count >> 8; 1235443Sgblack@eecs.umich.edu break; 1245443Sgblack@eecs.umich.edu default: 1255443Sgblack@eecs.umich.edu panic("Shouldn't be here"); 1265443Sgblack@eecs.umich.edu } 1275443Sgblack@eecs.umich.edu } else { 1285443Sgblack@eecs.umich.edu switch (read_byte) { 1295443Sgblack@eecs.umich.edu case LSB: 1305443Sgblack@eecs.umich.edu read_byte = MSB; 1315443Sgblack@eecs.umich.edu return (uint8_t)count; 1325443Sgblack@eecs.umich.edu break; 1335443Sgblack@eecs.umich.edu case MSB: 1345443Sgblack@eecs.umich.edu read_byte = LSB; 1355443Sgblack@eecs.umich.edu return count >> 8; 1365443Sgblack@eecs.umich.edu break; 1375443Sgblack@eecs.umich.edu default: 1385443Sgblack@eecs.umich.edu panic("Shouldn't be here"); 1395443Sgblack@eecs.umich.edu } 1405443Sgblack@eecs.umich.edu } 1415443Sgblack@eecs.umich.edu} 1425443Sgblack@eecs.umich.edu 1435443Sgblack@eecs.umich.eduvoid 1445443Sgblack@eecs.umich.eduIntel8254Timer::Counter::write(const uint8_t data) 1455443Sgblack@eecs.umich.edu{ 1465443Sgblack@eecs.umich.edu switch (write_byte) { 1475443Sgblack@eecs.umich.edu case LSB: 1485443Sgblack@eecs.umich.edu count = (count & 0xFF00) | data; 1495443Sgblack@eecs.umich.edu 1505443Sgblack@eecs.umich.edu if (event.scheduled()) 1515606Snate@binkert.org parent->deschedule(event); 1525443Sgblack@eecs.umich.edu output_high = false; 1535443Sgblack@eecs.umich.edu write_byte = MSB; 1545443Sgblack@eecs.umich.edu break; 1555443Sgblack@eecs.umich.edu 1565443Sgblack@eecs.umich.edu case MSB: 1575443Sgblack@eecs.umich.edu count = (count & 0x00FF) | (data << 8); 1585444Sgblack@eecs.umich.edu // In the RateGen or SquareWave modes, the timer wraps around and 1595444Sgblack@eecs.umich.edu // triggers on a value of 1, not 0. 1605444Sgblack@eecs.umich.edu if (mode == RateGen || mode == SquareWave) 1615444Sgblack@eecs.umich.edu period = count - 1; 1625444Sgblack@eecs.umich.edu else 1635444Sgblack@eecs.umich.edu period = count; 1645443Sgblack@eecs.umich.edu 1655444Sgblack@eecs.umich.edu if (period > 0) 1665444Sgblack@eecs.umich.edu event.setTo(period); 1675444Sgblack@eecs.umich.edu 1685443Sgblack@eecs.umich.edu write_byte = LSB; 1695443Sgblack@eecs.umich.edu break; 1705443Sgblack@eecs.umich.edu } 1715443Sgblack@eecs.umich.edu} 1725443Sgblack@eecs.umich.edu 1735443Sgblack@eecs.umich.eduvoid 1745443Sgblack@eecs.umich.eduIntel8254Timer::Counter::setRW(int rw_val) 1755443Sgblack@eecs.umich.edu{ 1765443Sgblack@eecs.umich.edu if (rw_val != TwoPhase) 1775443Sgblack@eecs.umich.edu panic("Only LSB/MSB read/write is implemented.\n"); 1785443Sgblack@eecs.umich.edu} 1795443Sgblack@eecs.umich.edu 1805443Sgblack@eecs.umich.eduvoid 1815443Sgblack@eecs.umich.eduIntel8254Timer::Counter::setMode(int mode_val) 1825443Sgblack@eecs.umich.edu{ 1835443Sgblack@eecs.umich.edu if(mode_val != InitTc && mode_val != RateGen && 1845443Sgblack@eecs.umich.edu mode_val != SquareWave) 1855443Sgblack@eecs.umich.edu panic("PIT mode %#x is not implemented: \n", mode_val); 1865443Sgblack@eecs.umich.edu 1875443Sgblack@eecs.umich.edu mode = mode_val; 1885443Sgblack@eecs.umich.edu} 1895443Sgblack@eecs.umich.edu 1905443Sgblack@eecs.umich.eduvoid 1915443Sgblack@eecs.umich.eduIntel8254Timer::Counter::setBCD(int bcd_val) 1925443Sgblack@eecs.umich.edu{ 1935443Sgblack@eecs.umich.edu if (bcd_val) 1945443Sgblack@eecs.umich.edu panic("PITimer does not implement BCD counts.\n"); 1955443Sgblack@eecs.umich.edu} 1965443Sgblack@eecs.umich.edu 1975443Sgblack@eecs.umich.edubool 1985443Sgblack@eecs.umich.eduIntel8254Timer::Counter::outputHigh() 1995443Sgblack@eecs.umich.edu{ 2005443Sgblack@eecs.umich.edu return output_high; 2015443Sgblack@eecs.umich.edu} 2025443Sgblack@eecs.umich.edu 2035443Sgblack@eecs.umich.eduvoid 2045443Sgblack@eecs.umich.eduIntel8254Timer::Counter::serialize(const string &base, ostream &os) 2055443Sgblack@eecs.umich.edu{ 2065443Sgblack@eecs.umich.edu paramOut(os, base + ".count", count); 2075443Sgblack@eecs.umich.edu paramOut(os, base + ".latched_count", latched_count); 2085443Sgblack@eecs.umich.edu paramOut(os, base + ".period", period); 2095443Sgblack@eecs.umich.edu paramOut(os, base + ".mode", mode); 2105443Sgblack@eecs.umich.edu paramOut(os, base + ".output_high", output_high); 2115443Sgblack@eecs.umich.edu paramOut(os, base + ".latch_on", latch_on); 2125443Sgblack@eecs.umich.edu paramOut(os, base + ".read_byte", read_byte); 2135443Sgblack@eecs.umich.edu paramOut(os, base + ".write_byte", write_byte); 2145443Sgblack@eecs.umich.edu 2155443Sgblack@eecs.umich.edu Tick event_tick = 0; 2165443Sgblack@eecs.umich.edu if (event.scheduled()) 2175443Sgblack@eecs.umich.edu event_tick = event.when(); 2185443Sgblack@eecs.umich.edu paramOut(os, base + ".event_tick", event_tick); 2195443Sgblack@eecs.umich.edu} 2205443Sgblack@eecs.umich.edu 2215443Sgblack@eecs.umich.eduvoid 2225443Sgblack@eecs.umich.eduIntel8254Timer::Counter::unserialize(const string &base, Checkpoint *cp, 2235443Sgblack@eecs.umich.edu const string §ion) 2245443Sgblack@eecs.umich.edu{ 2255443Sgblack@eecs.umich.edu paramIn(cp, section, base + ".count", count); 2265443Sgblack@eecs.umich.edu paramIn(cp, section, base + ".latched_count", latched_count); 2275443Sgblack@eecs.umich.edu paramIn(cp, section, base + ".period", period); 2285443Sgblack@eecs.umich.edu paramIn(cp, section, base + ".mode", mode); 2295443Sgblack@eecs.umich.edu paramIn(cp, section, base + ".output_high", output_high); 2305443Sgblack@eecs.umich.edu paramIn(cp, section, base + ".latch_on", latch_on); 2315443Sgblack@eecs.umich.edu paramIn(cp, section, base + ".read_byte", read_byte); 2325443Sgblack@eecs.umich.edu paramIn(cp, section, base + ".write_byte", write_byte); 2335443Sgblack@eecs.umich.edu 2345443Sgblack@eecs.umich.edu Tick event_tick; 2355443Sgblack@eecs.umich.edu paramIn(cp, section, base + ".event_tick", event_tick); 2365443Sgblack@eecs.umich.edu if (event_tick) 2375606Snate@binkert.org parent->schedule(event, event_tick); 2385443Sgblack@eecs.umich.edu} 2395443Sgblack@eecs.umich.edu 2405443Sgblack@eecs.umich.eduIntel8254Timer::Counter::CounterEvent::CounterEvent(Counter* c_ptr) 2415443Sgblack@eecs.umich.edu{ 2425443Sgblack@eecs.umich.edu interval = (Tick)(Clock::Float::s / 1193180.0); 2435443Sgblack@eecs.umich.edu counter = c_ptr; 2445443Sgblack@eecs.umich.edu} 2455443Sgblack@eecs.umich.edu 2465443Sgblack@eecs.umich.eduvoid 2475443Sgblack@eecs.umich.eduIntel8254Timer::Counter::CounterEvent::process() 2485443Sgblack@eecs.umich.edu{ 2495443Sgblack@eecs.umich.edu DPRINTF(Intel8254Timer, "Timer Interrupt\n"); 2505443Sgblack@eecs.umich.edu switch (counter->mode) { 2515443Sgblack@eecs.umich.edu case InitTc: 2525443Sgblack@eecs.umich.edu counter->output_high = true; 2535444Sgblack@eecs.umich.edu break; 2545443Sgblack@eecs.umich.edu case RateGen: 2555443Sgblack@eecs.umich.edu case SquareWave: 2565444Sgblack@eecs.umich.edu setTo(counter->period); 2575443Sgblack@eecs.umich.edu break; 2585443Sgblack@eecs.umich.edu default: 2595443Sgblack@eecs.umich.edu panic("Unimplemented PITimer mode.\n"); 2605443Sgblack@eecs.umich.edu } 2615443Sgblack@eecs.umich.edu} 2625443Sgblack@eecs.umich.edu 2635444Sgblack@eecs.umich.eduvoid 2645444Sgblack@eecs.umich.eduIntel8254Timer::Counter::CounterEvent::setTo(int clocks) 2655444Sgblack@eecs.umich.edu{ 2665444Sgblack@eecs.umich.edu if (clocks == 0) 2675444Sgblack@eecs.umich.edu panic("Timer can't be set to go off instantly.\n"); 2685444Sgblack@eecs.umich.edu DPRINTF(Intel8254Timer, "Timer set to curTick + %d\n", 2695444Sgblack@eecs.umich.edu clocks * interval); 2705606Snate@binkert.org counter->parent->schedule(this, curTick + clocks * interval); 2715444Sgblack@eecs.umich.edu} 2725444Sgblack@eecs.umich.edu 2735443Sgblack@eecs.umich.educonst char * 2745443Sgblack@eecs.umich.eduIntel8254Timer::Counter::CounterEvent::description() const 2755443Sgblack@eecs.umich.edu{ 2765443Sgblack@eecs.umich.edu return "tsunami 8254 Interval timer"; 2775443Sgblack@eecs.umich.edu} 278