summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/dev/intel_8254_timer.cc39
-rw-r--r--src/dev/intel_8254_timer.hh9
2 files changed, 38 insertions, 10 deletions
diff --git a/src/dev/intel_8254_timer.cc b/src/dev/intel_8254_timer.cc
index d5dd043e1..770df1c76 100644
--- a/src/dev/intel_8254_timer.cc
+++ b/src/dev/intel_8254_timer.cc
@@ -90,7 +90,7 @@ Intel8254Timer::unserialize(const string &base, Checkpoint *cp,
Intel8254Timer::Counter::Counter(Intel8254Timer *p,
const string &name, unsigned int _num)
- : _name(name), num(_num), event(this), count(0),
+ : _name(name), num(_num), event(this), initial_count(0),
latched_count(0), period(0), mode(0), output_high(false),
latch_on(false), read_byte(LSB), write_byte(LSB), parent(p)
{
@@ -104,10 +104,24 @@ Intel8254Timer::Counter::latchCount()
if(!latch_on) {
latch_on = true;
read_byte = LSB;
- latched_count = count;
+ latched_count = currentCount();
}
}
+int
+Intel8254Timer::Counter::currentCount()
+{
+ int clocks = event.clocksLeft();
+ if (clocks == -1) {
+ warn_once("Reading current count from inactive timer.\n");
+ return 0;
+ }
+ if (mode == RateGen || mode == SquareWave)
+ return clocks + 1;
+ else
+ return clocks;
+}
+
uint8_t
Intel8254Timer::Counter::read()
{
@@ -126,6 +140,7 @@ Intel8254Timer::Counter::read()
panic("Shouldn't be here");
}
} else {
+ uint16_t count = currentCount();
switch (read_byte) {
case LSB:
read_byte = MSB;
@@ -146,7 +161,7 @@ Intel8254Timer::Counter::write(const uint8_t data)
{
switch (write_byte) {
case LSB:
- count = (count & 0xFF00) | data;
+ initial_count = (initial_count & 0xFF00) | data;
if (event.scheduled())
parent->deschedule(event);
@@ -155,13 +170,13 @@ Intel8254Timer::Counter::write(const uint8_t data)
break;
case MSB:
- count = (count & 0x00FF) | (data << 8);
+ initial_count = (initial_count & 0x00FF) | (data << 8);
// In the RateGen or SquareWave modes, the timer wraps around and
// triggers on a value of 1, not 0.
if (mode == RateGen || mode == SquareWave)
- period = count - 1;
+ period = initial_count - 1;
else
- period = count;
+ period = initial_count;
if (period > 0)
event.setTo(period);
@@ -204,7 +219,7 @@ Intel8254Timer::Counter::outputHigh()
void
Intel8254Timer::Counter::serialize(const string &base, ostream &os)
{
- paramOut(os, base + ".count", count);
+ paramOut(os, base + ".initial_count", initial_count);
paramOut(os, base + ".latched_count", latched_count);
paramOut(os, base + ".period", period);
paramOut(os, base + ".mode", mode);
@@ -223,7 +238,7 @@ void
Intel8254Timer::Counter::unserialize(const string &base, Checkpoint *cp,
const string &section)
{
- paramIn(cp, section, base + ".count", count);
+ paramIn(cp, section, base + ".initial_count", initial_count);
paramIn(cp, section, base + ".latched_count", latched_count);
paramIn(cp, section, base + ".period", period);
paramIn(cp, section, base + ".mode", mode);
@@ -271,6 +286,14 @@ Intel8254Timer::Counter::CounterEvent::setTo(int clocks)
counter->parent->schedule(this, curTick + clocks * interval);
}
+int
+Intel8254Timer::Counter::CounterEvent::clocksLeft()
+{
+ if (!scheduled())
+ return -1;
+ return (when() - curTick + interval - 1) / interval;
+}
+
const char *
Intel8254Timer::Counter::CounterEvent::description() const
{
diff --git a/src/dev/intel_8254_timer.hh b/src/dev/intel_8254_timer.hh
index bb650d33b..1bc2ab87b 100644
--- a/src/dev/intel_8254_timer.hh
+++ b/src/dev/intel_8254_timer.hh
@@ -98,6 +98,8 @@ class Intel8254Timer : public EventManager
friend class Counter;
void setTo(int clocks);
+
+ int clocksLeft();
};
private:
@@ -108,8 +110,8 @@ class Intel8254Timer : public EventManager
CounterEvent event;
- /** Current count value */
- uint16_t count;
+ /** Initial count value */
+ uint16_t initial_count;
/** Latched count */
uint16_t latched_count;
@@ -141,6 +143,9 @@ class Intel8254Timer : public EventManager
/** Latch the current count (if one is not already latched) */
void latchCount();
+ /** Get the current count for this counter */
+ int currentCount();
+
/** Set the read/write mode */
void setRW(int rw_val);