intel_8254_timer.cc revision 6067:c633cdd5ca25
18706Sandreas.hansson@arm.com/*
28706Sandreas.hansson@arm.com * Copyright (c) 2004, 2005
38706Sandreas.hansson@arm.com * The Regents of The University of Michigan
48706Sandreas.hansson@arm.com * All Rights Reserved
58706Sandreas.hansson@arm.com *
68706Sandreas.hansson@arm.com * This code is part of the M5 simulator.
78706Sandreas.hansson@arm.com *
88706Sandreas.hansson@arm.com * Permission is granted to use, copy, create derivative works and
98706Sandreas.hansson@arm.com * redistribute this software and such derivative works for any
108706Sandreas.hansson@arm.com * purpose, so long as the copyright notice above, this grant of
118706Sandreas.hansson@arm.com * permission, and the disclaimer below appear in all copies made; and
128706Sandreas.hansson@arm.com * so long as the name of The University of Michigan is not used in
136892SBrad.Beckmann@amd.com * any advertising or publicity pertaining to the use or distribution
146892SBrad.Beckmann@amd.com * of this software without specific, written prior authorization.
156892SBrad.Beckmann@amd.com *
166892SBrad.Beckmann@amd.com * THIS SOFTWARE IS PROVIDED AS IS, WITHOUT REPRESENTATION FROM THE
176892SBrad.Beckmann@amd.com * UNIVERSITY OF MICHIGAN AS TO ITS FITNESS FOR ANY PURPOSE, AND
186892SBrad.Beckmann@amd.com * WITHOUT WARRANTY BY THE UNIVERSITY OF MICHIGAN OF ANY KIND, EITHER
196892SBrad.Beckmann@amd.com * EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED
206892SBrad.Beckmann@amd.com * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
216892SBrad.Beckmann@amd.com * PURPOSE. THE REGENTS OF THE UNIVERSITY OF MICHIGAN SHALL NOT BE
226892SBrad.Beckmann@amd.com * LIABLE FOR ANY DAMAGES, INCLUDING DIRECT, SPECIAL, INDIRECT,
236892SBrad.Beckmann@amd.com * INCIDENTAL, OR CONSEQUENTIAL DAMAGES, WITH RESPECT TO ANY CLAIM
246892SBrad.Beckmann@amd.com * ARISING OUT OF OR IN CONNECTION WITH THE USE OF THE SOFTWARE, EVEN
256892SBrad.Beckmann@amd.com * IF IT HAS BEEN OR IS HEREAFTER ADVISED OF THE POSSIBILITY OF SUCH
266892SBrad.Beckmann@amd.com * DAMAGES.
276892SBrad.Beckmann@amd.com *
286892SBrad.Beckmann@amd.com * Authors: Ali G. Saidi
296892SBrad.Beckmann@amd.com *          Andrew L. Schultz
306892SBrad.Beckmann@amd.com *          Miguel J. Serrano
316892SBrad.Beckmann@amd.com */
326892SBrad.Beckmann@amd.com
336892SBrad.Beckmann@amd.com#include "base/misc.hh"
346892SBrad.Beckmann@amd.com#include "dev/intel_8254_timer.hh"
356892SBrad.Beckmann@amd.com
366892SBrad.Beckmann@amd.comusing namespace std;
376892SBrad.Beckmann@amd.com
386892SBrad.Beckmann@amd.comIntel8254Timer::Intel8254Timer(EventManager *em, const string &name,
396892SBrad.Beckmann@amd.com    Counter *counter0, Counter *counter1, Counter *counter2) :
406892SBrad.Beckmann@amd.com    EventManager(em), _name(name)
416892SBrad.Beckmann@amd.com{
427563SBrad.Beckmann@amd.com    counter[0] = counter0;
436892SBrad.Beckmann@amd.com    counter[1] = counter1;
446892SBrad.Beckmann@amd.com    counter[2] = counter2;
456892SBrad.Beckmann@amd.com}
466892SBrad.Beckmann@amd.com
477538SBrad.Beckmann@amd.comIntel8254Timer::Intel8254Timer(EventManager *em, const string &name) :
488939SBrad.Beckmann@amd.com    EventManager(em), _name(name)
498939SBrad.Beckmann@amd.com{
508939SBrad.Beckmann@amd.com    counter[0] = new Counter(this, name + ".counter0", 0);
517538SBrad.Beckmann@amd.com    counter[1] = new Counter(this, name + ".counter1", 1);
527538SBrad.Beckmann@amd.com    counter[2] = new Counter(this, name + ".counter2", 2);
537538SBrad.Beckmann@amd.com}
547538SBrad.Beckmann@amd.com
557538SBrad.Beckmann@amd.comvoid
567661Snate@binkert.orgIntel8254Timer::writeControl(const CtrlReg data)
577538SBrad.Beckmann@amd.com{
588612Stushar@csail.mit.edu    int sel = data.sel;
598612Stushar@csail.mit.edu
607538SBrad.Beckmann@amd.com    if (sel == ReadBackCommand)
617538SBrad.Beckmann@amd.com       panic("PITimer Read-Back Command is not implemented.\n");
627917SBrad.Beckmann@amd.com
637563SBrad.Beckmann@amd.com    if (data.rw == LatchCommand)
647563SBrad.Beckmann@amd.com        counter[sel]->latchCount();
657538SBrad.Beckmann@amd.com    else {
667538SBrad.Beckmann@amd.com        counter[sel]->setRW(data.rw);
677538SBrad.Beckmann@amd.com        counter[sel]->setMode(data.mode);
687538SBrad.Beckmann@amd.com        counter[sel]->setBCD(data.bcd);
697538SBrad.Beckmann@amd.com    }
707566SBrad.Beckmann@amd.com}
717566SBrad.Beckmann@amd.com
727809Snilay@cs.wisc.eduvoid
737809Snilay@cs.wisc.eduIntel8254Timer::serialize(const string &base, ostream &os)
747809Snilay@cs.wisc.edu{
757809Snilay@cs.wisc.edu    // serialize the counters
768638Sgloh    counter[0]->serialize(base + ".counter0", os);
778638Sgloh    counter[1]->serialize(base + ".counter1", os);
787538SBrad.Beckmann@amd.com    counter[2]->serialize(base + ".counter2", os);
797538SBrad.Beckmann@amd.com}
807538SBrad.Beckmann@amd.com
817538SBrad.Beckmann@amd.comvoid
829100SBrad.Beckmann@amd.comIntel8254Timer::unserialize(const string &base, Checkpoint *cp,
839100SBrad.Beckmann@amd.com        const string &section)
849100SBrad.Beckmann@amd.com{
859100SBrad.Beckmann@amd.com    // unserialze the counters
869100SBrad.Beckmann@amd.com    counter[0]->unserialize(base + ".counter0", cp, section);
879100SBrad.Beckmann@amd.com    counter[1]->unserialize(base + ".counter1", cp, section);
889100SBrad.Beckmann@amd.com    counter[2]->unserialize(base + ".counter2", cp, section);
899100SBrad.Beckmann@amd.com}
909100SBrad.Beckmann@amd.com
919100SBrad.Beckmann@amd.comIntel8254Timer::Counter::Counter(Intel8254Timer *p,
928929Snilay@cs.wisc.edu        const string &name, unsigned int _num)
936892SBrad.Beckmann@amd.com    : _name(name), num(_num), event(this), initial_count(0),
948638Sgloh      latched_count(0), period(0), mode(0), output_high(false),
958690Snilay@cs.wisc.edu      latch_on(false), read_byte(LSB), write_byte(LSB), parent(p)
968690Snilay@cs.wisc.edu{
978436SBrad.Beckmann@amd.com
988436SBrad.Beckmann@amd.com}
997032SBrad.Beckmann@amd.com
1007032SBrad.Beckmann@amd.comvoid
1016923SBrad.Beckmann@amd.comIntel8254Timer::Counter::latchCount()
1029100SBrad.Beckmann@amd.com{
1038929Snilay@cs.wisc.edu    // behave like a real latch
1047557SBrad.Beckmann@amd.com    if(!latch_on) {
1056923SBrad.Beckmann@amd.com        latch_on = true;
1066923SBrad.Beckmann@amd.com        read_byte = LSB;
1077557SBrad.Beckmann@amd.com        latched_count = currentCount();
1088257SBrad.Beckmann@amd.com    }
1098706Sandreas.hansson@arm.com}
1108706Sandreas.hansson@arm.com
1118706Sandreas.hansson@arm.comint
1128923Sandreas.hansson@arm.comIntel8254Timer::Counter::currentCount()
1138706Sandreas.hansson@arm.com{
1148706Sandreas.hansson@arm.com    int clocks = event.clocksLeft();
1158706Sandreas.hansson@arm.com    if (clocks == -1) {
1168706Sandreas.hansson@arm.com        warn_once("Reading current count from inactive timer.\n");
1178732Sandreas.hansson@arm.com        return 0;
1188839Sandreas.hansson@arm.com    }
1198732Sandreas.hansson@arm.com    if (mode == RateGen || mode == SquareWave)
1208732Sandreas.hansson@arm.com        return clocks + 1;
1218257SBrad.Beckmann@amd.com    else
1228257SBrad.Beckmann@amd.com        return clocks;
1238257SBrad.Beckmann@amd.com}
1248257SBrad.Beckmann@amd.com
1258257SBrad.Beckmann@amd.comuint8_t
1268257SBrad.Beckmann@amd.comIntel8254Timer::Counter::read()
1278257SBrad.Beckmann@amd.com{
1288257SBrad.Beckmann@amd.com    if (latch_on) {
1298257SBrad.Beckmann@amd.com        switch (read_byte) {
1308257SBrad.Beckmann@amd.com          case LSB:
1318257SBrad.Beckmann@amd.com            read_byte = MSB;
1328257SBrad.Beckmann@amd.com            return (uint8_t)latched_count;
1338257SBrad.Beckmann@amd.com            break;
1348257SBrad.Beckmann@amd.com          case MSB:
1358257SBrad.Beckmann@amd.com            read_byte = LSB;
1368258SBrad.Beckmann@amd.com            latch_on = false;
1378258SBrad.Beckmann@amd.com            return latched_count >> 8;
1389274Snilay@cs.wisc.edu            break;
1399148Spowerjg@cs.wisc.edu          default:
1406892SBrad.Beckmann@amd.com            panic("Shouldn't be here");
1419100SBrad.Beckmann@amd.com        }
1429100SBrad.Beckmann@amd.com    } else {
1439148Spowerjg@cs.wisc.edu        uint16_t count = currentCount();
1446892SBrad.Beckmann@amd.com        switch (read_byte) {
1459148Spowerjg@cs.wisc.edu          case LSB:
1469148Spowerjg@cs.wisc.edu            read_byte = MSB;
1479148Spowerjg@cs.wisc.edu            return (uint8_t)count;
1489148Spowerjg@cs.wisc.edu            break;
1499148Spowerjg@cs.wisc.edu          case MSB:
1509148Spowerjg@cs.wisc.edu            read_byte = LSB;
1519148Spowerjg@cs.wisc.edu            return count >> 8;
1529148Spowerjg@cs.wisc.edu            break;
1539148Spowerjg@cs.wisc.edu          default:
1549148Spowerjg@cs.wisc.edu            panic("Shouldn't be here");
1559148Spowerjg@cs.wisc.edu        }
1568257SBrad.Beckmann@amd.com    }
1578612Stushar@csail.mit.edu}
1588612Stushar@csail.mit.edu
1598612Stushar@csail.mit.eduvoid
1608612Stushar@csail.mit.eduIntel8254Timer::Counter::write(const uint8_t data)
1618612Stushar@csail.mit.edu{
1628612Stushar@csail.mit.edu    switch (write_byte) {
1638612Stushar@csail.mit.edu      case LSB:
1646892SBrad.Beckmann@amd.com        initial_count = (initial_count & 0xFF00) | data;
1656903SBrad.Beckmann@amd.com
1667563SBrad.Beckmann@amd.com        if (event.scheduled())
1677025SBrad.Beckmann@amd.com            parent->deschedule(event);
1689148Spowerjg@cs.wisc.edu        output_high = false;
1697025SBrad.Beckmann@amd.com        write_byte = MSB;
1707025SBrad.Beckmann@amd.com        break;
1717563SBrad.Beckmann@amd.com
1726903SBrad.Beckmann@amd.com      case MSB:
1736903SBrad.Beckmann@amd.com        initial_count = (initial_count & 0x00FF) | (data << 8);
1747563SBrad.Beckmann@amd.com        // In the RateGen or SquareWave modes, the timer wraps around and
1757563SBrad.Beckmann@amd.com        // triggers on a value of 1, not 0.
1769318Spower.jg@gmail.com        if (mode == RateGen || mode == SquareWave)
1779318Spower.jg@gmail.com            period = initial_count - 1;
1787563SBrad.Beckmann@amd.com        else
1797563SBrad.Beckmann@amd.com            period = initial_count;
1807563SBrad.Beckmann@amd.com
1817563SBrad.Beckmann@amd.com        if (period > 0)
1829318Spower.jg@gmail.com            event.setTo(period);
1839318Spower.jg@gmail.com
1849318Spower.jg@gmail.com        write_byte = LSB;
1859318Spower.jg@gmail.com        break;
1869148Spowerjg@cs.wisc.edu    }
1876903SBrad.Beckmann@amd.com}
1886903SBrad.Beckmann@amd.com
1897563SBrad.Beckmann@amd.comvoid
1909148Spowerjg@cs.wisc.eduIntel8254Timer::Counter::setRW(int rw_val)
1919232Sandreas.hansson@arm.com{
1929232Sandreas.hansson@arm.com    if (rw_val != TwoPhase)
1938931Sandreas.hansson@arm.com        panic("Only LSB/MSB read/write is implemented.\n");
1946892SBrad.Beckmann@amd.com}
1958436SBrad.Beckmann@amd.com
1968436SBrad.Beckmann@amd.comvoid
1978436SBrad.Beckmann@amd.comIntel8254Timer::Counter::setMode(int mode_val)
1988436SBrad.Beckmann@amd.com{
1998436SBrad.Beckmann@amd.com    if(mode_val != InitTc && mode_val != RateGen &&
2008322Ssteve.reinhardt@amd.com       mode_val != SquareWave)
2017809Snilay@cs.wisc.edu        panic("PIT mode %#x is not implemented: \n", mode_val);
202
203    mode = mode_val;
204}
205
206void
207Intel8254Timer::Counter::setBCD(int bcd_val)
208{
209    if (bcd_val)
210        panic("PITimer does not implement BCD counts.\n");
211}
212
213bool
214Intel8254Timer::Counter::outputHigh()
215{
216    return output_high;
217}
218
219void
220Intel8254Timer::Counter::serialize(const string &base, ostream &os)
221{
222    paramOut(os, base + ".initial_count", initial_count);
223    paramOut(os, base + ".latched_count", latched_count);
224    paramOut(os, base + ".period", period);
225    paramOut(os, base + ".mode", mode);
226    paramOut(os, base + ".output_high", output_high);
227    paramOut(os, base + ".latch_on", latch_on);
228    paramOut(os, base + ".read_byte", read_byte);
229    paramOut(os, base + ".write_byte", write_byte);
230
231    Tick event_tick = 0;
232    if (event.scheduled())
233        event_tick = event.when();
234    paramOut(os, base + ".event_tick", event_tick);
235}
236
237void
238Intel8254Timer::Counter::unserialize(const string &base, Checkpoint *cp,
239                                         const string &section)
240{
241    paramIn(cp, section, base + ".initial_count", initial_count);
242    paramIn(cp, section, base + ".latched_count", latched_count);
243    paramIn(cp, section, base + ".period", period);
244    paramIn(cp, section, base + ".mode", mode);
245    paramIn(cp, section, base + ".output_high", output_high);
246    paramIn(cp, section, base + ".latch_on", latch_on);
247    paramIn(cp, section, base + ".read_byte", read_byte);
248    paramIn(cp, section, base + ".write_byte", write_byte);
249
250    Tick event_tick;
251    paramIn(cp, section, base + ".event_tick", event_tick);
252    if (event_tick)
253        parent->schedule(event, event_tick);
254}
255
256Intel8254Timer::Counter::CounterEvent::CounterEvent(Counter* c_ptr)
257{
258    interval = (Tick)(Clock::Float::s / 1193180.0);
259    counter = c_ptr;
260}
261
262void
263Intel8254Timer::Counter::CounterEvent::process()
264{
265    switch (counter->mode) {
266      case InitTc:
267        counter->output_high = true;
268        break;
269      case RateGen:
270      case SquareWave:
271        setTo(counter->period);
272        break;
273      default:
274        panic("Unimplemented PITimer mode.\n");
275    }
276    counter->parent->counterInterrupt(counter->num);
277}
278
279void
280Intel8254Timer::Counter::CounterEvent::setTo(int clocks)
281{
282    if (clocks == 0)
283        panic("Timer can't be set to go off instantly.\n");
284    DPRINTF(Intel8254Timer, "Timer set to curTick + %d\n",
285            clocks * interval);
286    counter->parent->schedule(this, curTick + clocks * interval);
287}
288
289int
290Intel8254Timer::Counter::CounterEvent::clocksLeft()
291{
292    if (!scheduled())
293        return -1;
294    return (when() - curTick + interval - 1) / interval;
295}
296
297const char *
298Intel8254Timer::Counter::CounterEvent::description() const
299{
300    return "Intel 8254 Interval timer";
301}
302