devices: Fixed periodic interrupts to work with draining

Added drain functions to the RTC and 8254 timer so that periodic interrupts
stop when the system is draining.  This patch is needed to checkpoint in
timing mode.  Otherwise under certain situations, the event queue will never
be completely empty.
This commit is contained in:
Brad Beckmann 2010-08-20 11:46:13 -07:00
parent b6d08e0455
commit 283be34a99
6 changed files with 80 additions and 9 deletions

View file

@ -249,6 +249,17 @@ TsunamiIO::clearPIC(uint8_t bitvector)
}
}
unsigned int
TsunamiIO::drain(Event *de)
{
unsigned int count = 0;
count += pitimer.drain(de);
count += rtc.drain(de);
assert(count == 0);
changeState(SimObject::Drained);
return count;
}
void
TsunamiIO::serialize(ostream &os)
{

View file

@ -140,6 +140,12 @@ class TsunamiIO : public BasicPioDevice
*/
void clearPIC(uint8_t bitvector);
/**
* Drain the io state including all associated events.
* @param drainEvent
*/
unsigned int drain(Event *de);
/**
* Serialize this object to the given output stream.
* @param os The stream to serialize to.

View file

@ -32,6 +32,7 @@
#include "base/misc.hh"
#include "dev/intel_8254_timer.hh"
#include "sim/sim_object.hh"
using namespace std;
@ -69,6 +70,17 @@ Intel8254Timer::writeControl(const CtrlReg data)
}
}
unsigned int
Intel8254Timer::drain(Event *de)
{
unsigned int count = 0;
count += counter[0]->drain(de);
count += counter[1]->drain(de);
count += counter[2]->drain(de);
assert(count == 0);
return count;
}
void
Intel8254Timer::serialize(const string &base, ostream &os)
{
@ -216,6 +228,18 @@ Intel8254Timer::Counter::outputHigh()
return output_high;
}
unsigned int
Intel8254Timer::Counter::drain(Event *de)
{
if (event.scheduled()) {
event_tick = event.when();
parent->deschedule(event);
} else {
event_tick = 0;
}
return 0;
}
void
Intel8254Timer::Counter::serialize(const string &base, ostream &os)
{
@ -227,10 +251,6 @@ Intel8254Timer::Counter::serialize(const string &base, ostream &os)
paramOut(os, base + ".latch_on", latch_on);
paramOut(os, base + ".read_byte", read_byte);
paramOut(os, base + ".write_byte", write_byte);
Tick event_tick = 0;
if (event.scheduled())
event_tick = event.when();
paramOut(os, base + ".event_tick", event_tick);
}
@ -247,7 +267,6 @@ Intel8254Timer::Counter::unserialize(const string &base, Checkpoint *cp,
paramIn(cp, section, base + ".read_byte", read_byte);
paramIn(cp, section, base + ".write_byte", write_byte);
Tick event_tick;
paramIn(cp, section, base + ".event_tick", event_tick);
if (event_tick)
parent->schedule(event, event_tick);

View file

@ -137,6 +137,10 @@ class Intel8254Timer : public EventManager
/** Pointer to container */
Intel8254Timer *parent;
/** if non-zero, the scheduled tick of an event used for drain
serialization coordination */
Tick event_tick;
public:
Counter(Intel8254Timer *p, const std::string &name, unsigned int num);
@ -164,6 +168,12 @@ class Intel8254Timer : public EventManager
/** Is the output high? */
bool outputHigh();
/**
* Drain all associated events.
* @param drainEvent
*/
unsigned int drain(Event *de);
/**
* Serialize this object to the given output stream.
* @param base The base name of the counter object.
@ -229,6 +239,8 @@ class Intel8254Timer : public EventManager
return counter[num]->outputHigh();
}
unsigned int drain(Event *de);
/**
* Serialize this object to the given output stream.
* @param base The base name of the counter object.

View file

@ -40,6 +40,7 @@
#include "base/trace.hh"
#include "dev/mc146818.hh"
#include "dev/rtcreg.h"
#include "sim/sim_object.hh"
using namespace std;
@ -105,8 +106,12 @@ MC146818::MC146818(EventManager *em, const string &n, const struct tm time,
MC146818::~MC146818()
{
deschedule(tickEvent);
deschedule(event);
if (tickEvent.scheduled()) {
deschedule(tickEvent);
}
if (event.scheduled()) {
deschedule(event);
}
}
void
@ -203,6 +208,20 @@ MC146818::tickClock()
setTime(*gmtime(&calTime));
}
unsigned int
MC146818::drain(Event *de)
{
if (event.scheduled()) {
rtcTimerInterruptTickOffset = event.when() - curTick;
rtcClockTickOffset = event.when() - curTick;
deschedule(event);
}
if (tickEvent.scheduled()) {
deschedule(tickEvent);
}
return 0;
}
void
MC146818::serialize(const string &base, ostream &os)
{
@ -214,9 +233,7 @@ MC146818::serialize(const string &base, ostream &os)
// save the timer tick and rtc clock tick values to correctly reschedule
// them during unserialize
//
Tick rtcTimerInterruptTickOffset = event.when() - curTick;
SERIALIZE_SCALAR(rtcTimerInterruptTickOffset);
Tick rtcClockTickOffset = event.when() - curTick;
SERIALIZE_SCALAR(rtcClockTickOffset);
}

View file

@ -119,6 +119,10 @@ class MC146818 : public EventManager
/** RTC status register B */
uint8_t stat_regB;
/** RTC event times for drain and serialization coordination */
Tick rtcTimerInterruptTickOffset;
Tick rtcClockTickOffset;
public:
MC146818(EventManager *em, const std::string &name, const struct tm time,
bool bcd, Tick frequency);
@ -132,6 +136,8 @@ class MC146818 : public EventManager
void tickClock();
unsigned int drain(Event *de);
/**
* Serialize this object to the given output stream.
* @param base The base name of the counter object.