intel_8254_timer.cc revision 7903
1955SN/A/* 2955SN/A * Copyright (c) 2004, 2005 31762SN/A * The Regents of The University of Michigan 4955SN/A * All Rights Reserved 5955SN/A * 6955SN/A * This code is part of the M5 simulator. 7955SN/A * 8955SN/A * Permission is granted to use, copy, create derivative works and 9955SN/A * redistribute this software and such derivative works for any 10955SN/A * purpose, so long as the copyright notice above, this grant of 11955SN/A * permission, and the disclaimer below appear in all copies made; and 12955SN/A * so long as the name of The University of Michigan is not used in 13955SN/A * any advertising or publicity pertaining to the use or distribution 14955SN/A * of this software without specific, written prior authorization. 15955SN/A * 16955SN/A * THIS SOFTWARE IS PROVIDED AS IS, WITHOUT REPRESENTATION FROM THE 17955SN/A * UNIVERSITY OF MICHIGAN AS TO ITS FITNESS FOR ANY PURPOSE, AND 18955SN/A * WITHOUT WARRANTY BY THE UNIVERSITY OF MICHIGAN OF ANY KIND, EITHER 19955SN/A * EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED 20955SN/A * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 21955SN/A * PURPOSE. THE REGENTS OF THE UNIVERSITY OF MICHIGAN SHALL NOT BE 22955SN/A * LIABLE FOR ANY DAMAGES, INCLUDING DIRECT, SPECIAL, INDIRECT, 23955SN/A * INCIDENTAL, OR CONSEQUENTIAL DAMAGES, WITH RESPECT TO ANY CLAIM 24955SN/A * ARISING OUT OF OR IN CONNECTION WITH THE USE OF THE SOFTWARE, EVEN 25955SN/A * IF IT HAS BEEN OR IS HEREAFTER ADVISED OF THE POSSIBILITY OF SUCH 26955SN/A * DAMAGES. 27955SN/A * 282665Ssaidi@eecs.umich.edu * Authors: Ali G. Saidi 294762Snate@binkert.org * Andrew L. Schultz 30955SN/A * Miguel J. Serrano 315522Snate@binkert.org */ 326143Snate@binkert.org 334762Snate@binkert.org#include "base/misc.hh" 345522Snate@binkert.org#include "dev/intel_8254_timer.hh" 35955SN/A 365522Snate@binkert.orgusing namespace std; 3711974Sgabeblack@google.com 38955SN/AIntel8254Timer::Intel8254Timer(EventManager *em, const string &name, 395522Snate@binkert.org Counter *counter0, Counter *counter1, Counter *counter2) : 404202Sbinkertn@umich.edu EventManager(em), _name(name) 415742Snate@binkert.org{ 42955SN/A counter[0] = counter0; 434381Sbinkertn@umich.edu counter[1] = counter1; 444381Sbinkertn@umich.edu counter[2] = counter2; 4512246Sgabeblack@google.com} 4612246Sgabeblack@google.com 478334Snate@binkert.orgIntel8254Timer::Intel8254Timer(EventManager *em, const string &name) : 48955SN/A EventManager(em), _name(name) 49955SN/A{ 504202Sbinkertn@umich.edu counter[0] = new Counter(this, name + ".counter0", 0); 51955SN/A counter[1] = new Counter(this, name + ".counter1", 1); 524382Sbinkertn@umich.edu counter[2] = new Counter(this, name + ".counter2", 2); 534382Sbinkertn@umich.edu} 544382Sbinkertn@umich.edu 556654Snate@binkert.orgvoid 565517Snate@binkert.orgIntel8254Timer::writeControl(const CtrlReg data) 578614Sgblack@eecs.umich.edu{ 587674Snate@binkert.org int sel = data.sel; 596143Snate@binkert.org 606143Snate@binkert.org if (sel == ReadBackCommand) 616143Snate@binkert.org panic("PITimer Read-Back Command is not implemented.\n"); 6212302Sgabeblack@google.com 6312302Sgabeblack@google.com if (data.rw == LatchCommand) 6412302Sgabeblack@google.com counter[sel]->latchCount(); 6512302Sgabeblack@google.com else { 6612302Sgabeblack@google.com counter[sel]->setRW(data.rw); 6712302Sgabeblack@google.com counter[sel]->setMode(data.mode); 6812302Sgabeblack@google.com counter[sel]->setBCD(data.bcd); 6912302Sgabeblack@google.com } 7012302Sgabeblack@google.com} 7112302Sgabeblack@google.com 7212302Sgabeblack@google.comvoid 7312302Sgabeblack@google.comIntel8254Timer::serialize(const string &base, ostream &os) 7412302Sgabeblack@google.com{ 7512302Sgabeblack@google.com // serialize the counters 7612302Sgabeblack@google.com counter[0]->serialize(base + ".counter0", os); 7712302Sgabeblack@google.com counter[1]->serialize(base + ".counter1", os); 7812302Sgabeblack@google.com counter[2]->serialize(base + ".counter2", os); 7912302Sgabeblack@google.com} 8012302Sgabeblack@google.com 8112302Sgabeblack@google.comvoid 8212302Sgabeblack@google.comIntel8254Timer::unserialize(const string &base, Checkpoint *cp, 8312302Sgabeblack@google.com const string §ion) 8412302Sgabeblack@google.com{ 8512302Sgabeblack@google.com // unserialze the counters 8612302Sgabeblack@google.com counter[0]->unserialize(base + ".counter0", cp, section); 8712302Sgabeblack@google.com counter[1]->unserialize(base + ".counter1", cp, section); 8812302Sgabeblack@google.com counter[2]->unserialize(base + ".counter2", cp, section); 8912302Sgabeblack@google.com} 9012302Sgabeblack@google.com 9111983Sgabeblack@google.comIntel8254Timer::Counter::Counter(Intel8254Timer *p, 926143Snate@binkert.org const string &name, unsigned int _num) 938233Snate@binkert.org : _name(name), num(_num), event(this), initial_count(0), 9412302Sgabeblack@google.com latched_count(0), period(0), mode(0), output_high(false), 956143Snate@binkert.org latch_on(false), read_byte(LSB), write_byte(LSB), parent(p) 966143Snate@binkert.org{ 9712302Sgabeblack@google.com 984762Snate@binkert.org} 996143Snate@binkert.org 1008233Snate@binkert.orgvoid 1018233Snate@binkert.orgIntel8254Timer::Counter::latchCount() 10212302Sgabeblack@google.com{ 10312302Sgabeblack@google.com // behave like a real latch 1046143Snate@binkert.org if(!latch_on) { 10512302Sgabeblack@google.com latch_on = true; 10612302Sgabeblack@google.com read_byte = LSB; 10712302Sgabeblack@google.com latched_count = currentCount(); 10812302Sgabeblack@google.com } 10912302Sgabeblack@google.com} 11012302Sgabeblack@google.com 11112302Sgabeblack@google.comint 11212302Sgabeblack@google.comIntel8254Timer::Counter::currentCount() 11312302Sgabeblack@google.com{ 11412302Sgabeblack@google.com int clocks = event.clocksLeft(); 1158233Snate@binkert.org if (clocks == -1) { 1166143Snate@binkert.org warn_once("Reading current count from inactive timer.\n"); 1176143Snate@binkert.org return 0; 1186143Snate@binkert.org } 1196143Snate@binkert.org if (mode == RateGen || mode == SquareWave) 1206143Snate@binkert.org return clocks + 1; 1216143Snate@binkert.org else 1226143Snate@binkert.org return clocks; 1236143Snate@binkert.org} 1246143Snate@binkert.org 1257065Snate@binkert.orguint8_t 1266143Snate@binkert.orgIntel8254Timer::Counter::read() 1278233Snate@binkert.org{ 1288233Snate@binkert.org if (latch_on) { 1298233Snate@binkert.org switch (read_byte) { 1308233Snate@binkert.org case LSB: 1318233Snate@binkert.org read_byte = MSB; 1328233Snate@binkert.org return (uint8_t)latched_count; 1338233Snate@binkert.org break; 1348233Snate@binkert.org case MSB: 1358233Snate@binkert.org read_byte = LSB; 1368233Snate@binkert.org latch_on = false; 1378233Snate@binkert.org return latched_count >> 8; 1388233Snate@binkert.org break; 1398233Snate@binkert.org default: 1408233Snate@binkert.org panic("Shouldn't be here"); 1418233Snate@binkert.org } 1428233Snate@binkert.org } else { 1438233Snate@binkert.org uint16_t count = currentCount(); 1448233Snate@binkert.org switch (read_byte) { 1458233Snate@binkert.org case LSB: 1468233Snate@binkert.org read_byte = MSB; 1478233Snate@binkert.org return (uint8_t)count; 1486143Snate@binkert.org break; 1496143Snate@binkert.org case MSB: 1506143Snate@binkert.org read_byte = LSB; 1516143Snate@binkert.org return count >> 8; 1526143Snate@binkert.org break; 1536143Snate@binkert.org default: 1549982Satgutier@umich.edu panic("Shouldn't be here"); 1556143Snate@binkert.org } 15612302Sgabeblack@google.com } 15712302Sgabeblack@google.com} 15812302Sgabeblack@google.com 15912302Sgabeblack@google.comvoid 16012302Sgabeblack@google.comIntel8254Timer::Counter::write(const uint8_t data) 16112302Sgabeblack@google.com{ 16212302Sgabeblack@google.com switch (write_byte) { 16312302Sgabeblack@google.com case LSB: 16411983Sgabeblack@google.com initial_count = (initial_count & 0xFF00) | data; 16511983Sgabeblack@google.com 16611983Sgabeblack@google.com if (event.scheduled()) 16712302Sgabeblack@google.com parent->deschedule(event); 16812302Sgabeblack@google.com output_high = false; 16912302Sgabeblack@google.com write_byte = MSB; 17012302Sgabeblack@google.com break; 17112302Sgabeblack@google.com 17212302Sgabeblack@google.com case MSB: 17311983Sgabeblack@google.com initial_count = (initial_count & 0x00FF) | (data << 8); 1746143Snate@binkert.org // In the RateGen or SquareWave modes, the timer wraps around and 17512305Sgabeblack@google.com // triggers on a value of 1, not 0. 17612302Sgabeblack@google.com if (mode == RateGen || mode == SquareWave) 17712302Sgabeblack@google.com period = initial_count - 1; 17812302Sgabeblack@google.com else 1796143Snate@binkert.org period = initial_count; 1806143Snate@binkert.org 1816143Snate@binkert.org if (period > 0) 1825522Snate@binkert.org event.setTo(period); 1836143Snate@binkert.org 1846143Snate@binkert.org write_byte = LSB; 1856143Snate@binkert.org break; 1869982Satgutier@umich.edu } 18712302Sgabeblack@google.com} 18812302Sgabeblack@google.com 18912302Sgabeblack@google.comvoid 1906143Snate@binkert.orgIntel8254Timer::Counter::setRW(int rw_val) 1916143Snate@binkert.org{ 1926143Snate@binkert.org if (rw_val != TwoPhase) 1936143Snate@binkert.org panic("Only LSB/MSB read/write is implemented.\n"); 1945522Snate@binkert.org} 1955522Snate@binkert.org 1965522Snate@binkert.orgvoid 1975522Snate@binkert.orgIntel8254Timer::Counter::setMode(int mode_val) 1985604Snate@binkert.org{ 1995604Snate@binkert.org if(mode_val != InitTc && mode_val != RateGen && 2006143Snate@binkert.org mode_val != SquareWave) 2016143Snate@binkert.org panic("PIT mode %#x is not implemented: \n", mode_val); 2024762Snate@binkert.org 2034762Snate@binkert.org mode = mode_val; 2046143Snate@binkert.org} 2056727Ssteve.reinhardt@amd.com 2066727Ssteve.reinhardt@amd.comvoid 2076727Ssteve.reinhardt@amd.comIntel8254Timer::Counter::setBCD(int bcd_val) 2084762Snate@binkert.org{ 2096143Snate@binkert.org if (bcd_val) 2106143Snate@binkert.org panic("PITimer does not implement BCD counts.\n"); 2116143Snate@binkert.org} 2126143Snate@binkert.org 2136727Ssteve.reinhardt@amd.combool 2146143Snate@binkert.orgIntel8254Timer::Counter::outputHigh() 2157674Snate@binkert.org{ 2167674Snate@binkert.org return output_high; 2175604Snate@binkert.org} 2186143Snate@binkert.org 2196143Snate@binkert.orgvoid 2206143Snate@binkert.orgIntel8254Timer::Counter::serialize(const string &base, ostream &os) 2214762Snate@binkert.org{ 2226143Snate@binkert.org paramOut(os, base + ".initial_count", initial_count); 2234762Snate@binkert.org paramOut(os, base + ".latched_count", latched_count); 2244762Snate@binkert.org paramOut(os, base + ".period", period); 2254762Snate@binkert.org paramOut(os, base + ".mode", mode); 2266143Snate@binkert.org paramOut(os, base + ".output_high", output_high); 2276143Snate@binkert.org paramOut(os, base + ".latch_on", latch_on); 2284762Snate@binkert.org paramOut(os, base + ".read_byte", read_byte); 22912302Sgabeblack@google.com paramOut(os, base + ".write_byte", write_byte); 23012302Sgabeblack@google.com 2318233Snate@binkert.org Tick event_tick = 0; 23212302Sgabeblack@google.com if (event.scheduled()) 2336143Snate@binkert.org event_tick = event.when(); 2346143Snate@binkert.org paramOut(os, base + ".event_tick", event_tick); 2354762Snate@binkert.org} 2366143Snate@binkert.org 2374762Snate@binkert.orgvoid 2389396Sandreas.hansson@arm.comIntel8254Timer::Counter::unserialize(const string &base, Checkpoint *cp, 2399396Sandreas.hansson@arm.com const string §ion) 2409396Sandreas.hansson@arm.com{ 24112302Sgabeblack@google.com paramIn(cp, section, base + ".initial_count", initial_count); 24212302Sgabeblack@google.com paramIn(cp, section, base + ".latched_count", latched_count); 24312302Sgabeblack@google.com paramIn(cp, section, base + ".period", period); 2449396Sandreas.hansson@arm.com paramIn(cp, section, base + ".mode", mode); 2459396Sandreas.hansson@arm.com paramIn(cp, section, base + ".output_high", output_high); 2469396Sandreas.hansson@arm.com paramIn(cp, section, base + ".latch_on", latch_on); 2479396Sandreas.hansson@arm.com paramIn(cp, section, base + ".read_byte", read_byte); 2489396Sandreas.hansson@arm.com paramIn(cp, section, base + ".write_byte", write_byte); 2499396Sandreas.hansson@arm.com 2509396Sandreas.hansson@arm.com Tick event_tick = 0; 2519930Sandreas.hansson@arm.com if (event.scheduled()) 2529930Sandreas.hansson@arm.com parent->deschedule(event); 2539396Sandreas.hansson@arm.com paramIn(cp, section, base + ".event_tick", event_tick); 2548235Snate@binkert.org if (event_tick) 2558235Snate@binkert.org parent->schedule(event, event_tick); 2566143Snate@binkert.org} 2578235Snate@binkert.org 2589003SAli.Saidi@ARM.comIntel8254Timer::Counter::CounterEvent::CounterEvent(Counter* c_ptr) 2598235Snate@binkert.org{ 2608235Snate@binkert.org interval = (Tick)(SimClock::Float::s / 1193180.0); 26112302Sgabeblack@google.com counter = c_ptr; 2628235Snate@binkert.org} 26312302Sgabeblack@google.com 2648235Snate@binkert.orgvoid 2658235Snate@binkert.orgIntel8254Timer::Counter::CounterEvent::process() 26612302Sgabeblack@google.com{ 2678235Snate@binkert.org switch (counter->mode) { 2688235Snate@binkert.org case InitTc: 2698235Snate@binkert.org counter->output_high = true; 2708235Snate@binkert.org break; 2719003SAli.Saidi@ARM.com case RateGen: 2728235Snate@binkert.org case SquareWave: 2735584Snate@binkert.org setTo(counter->period); 2744382Sbinkertn@umich.edu break; 2754202Sbinkertn@umich.edu default: 2764382Sbinkertn@umich.edu panic("Unimplemented PITimer mode.\n"); 2774382Sbinkertn@umich.edu } 2789396Sandreas.hansson@arm.com counter->parent->counterInterrupt(counter->num); 2795584Snate@binkert.org} 2804382Sbinkertn@umich.edu 2814382Sbinkertn@umich.eduvoid 2824382Sbinkertn@umich.eduIntel8254Timer::Counter::CounterEvent::setTo(int clocks) 2838232Snate@binkert.org{ 2845192Ssaidi@eecs.umich.edu if (clocks == 0) 2858232Snate@binkert.org panic("Timer can't be set to go off instantly.\n"); 2868232Snate@binkert.org DPRINTF(Intel8254Timer, "Timer set to curTick() + %d\n", 2878232Snate@binkert.org clocks * interval); 2885192Ssaidi@eecs.umich.edu counter->parent->schedule(this, curTick() + clocks * interval); 2898232Snate@binkert.org} 2905192Ssaidi@eecs.umich.edu 2915799Snate@binkert.orgint 2928232Snate@binkert.orgIntel8254Timer::Counter::CounterEvent::clocksLeft() 2935192Ssaidi@eecs.umich.edu{ 2945192Ssaidi@eecs.umich.edu if (!scheduled()) 2955192Ssaidi@eecs.umich.edu return -1; 2968232Snate@binkert.org return (when() - curTick() + interval - 1) / interval; 2975192Ssaidi@eecs.umich.edu} 2988232Snate@binkert.org 2995192Ssaidi@eecs.umich.educonst char * 3005192Ssaidi@eecs.umich.eduIntel8254Timer::Counter::CounterEvent::description() const 3015192Ssaidi@eecs.umich.edu{ 3025192Ssaidi@eecs.umich.edu return "Intel 8254 Interval timer"; 3034382Sbinkertn@umich.edu} 3044382Sbinkertn@umich.edu