Two fixes:

1. Make sure connectMemPorts() only gets called when the CPU's peer gets changed.  This is done by making setPeer() virtual, and overriding it in the CPU's ports.  When it gets called on a CPU's port (dcache specifically), it calls the normal setPeer() function, and also connectMemPorts().
2. Consolidate redundant code that handles switching in a CPU.

src/cpu/base.cc:
    Move common code of switching over peers to base CPU.
src/cpu/base.hh:
    Move common code of switching over peers to BaseCPU.
src/cpu/o3/cpu.cc:
    Add in function that updates thread context's ports.
    Also use updated function to takeOverFrom() in BaseCPU.  This gets rid of some repeated code.
src/cpu/o3/cpu.hh:
    Include function to update thread context's memory ports.
src/cpu/o3/lsq.hh:
    Add function to dcache port that will update the memory ports upon getting a new peer.
    Also include a function that will tell the CPU to update those memory ports.
src/cpu/o3/lsq_impl.hh:
    Add function that will update the memory ports upon getting a new peer.
src/cpu/simple/atomic.cc:
src/cpu/simple/timing.cc:
    Add function that will update thread context's memory ports upon getting a new peer.
    Also use the new BaseCPU's take over from function.
src/cpu/simple/atomic.hh:
    Add in function (and dcache port) that will allow the dcache to update memory ports when it gets assigned a new peer.
src/cpu/simple/timing.hh:
    Add function that will update thread context's memory ports upon getting a new peer.
src/mem/port.hh:
    Make setPeer virtual so that other classes can override it.

--HG--
extra : convert_revision : 2050f1241dd2e83875d281cfc5ad5c6c8705fdaf
This commit is contained in:
Kevin Lim
2007-03-09 10:06:09 -05:00
parent 1158da37fb
commit ad44834907
11 changed files with 100 additions and 64 deletions

View File

@@ -319,7 +319,7 @@ BaseCPU::switchOut()
}
void
BaseCPU::takeOverFrom(BaseCPU *oldCPU)
BaseCPU::takeOverFrom(BaseCPU *oldCPU, Port *ic, Port *dc)
{
assert(threadContexts.size() == oldCPU->threadContexts.size());
@@ -352,6 +352,26 @@ BaseCPU::takeOverFrom(BaseCPU *oldCPU)
// if (profileEvent)
// profileEvent->schedule(curTick);
#endif
// Connect new CPU to old CPU's memory only if new CPU isn't
// connected to anything. Also connect old CPU's memory to new
// CPU.
Port *peer;
if (ic->getPeer() == NULL) {
peer = oldCPU->getPort("icache_port")->getPeer();
ic->setPeer(peer);
} else {
peer = ic->getPeer();
}
peer->setPeer(ic);
if (dc->getPeer() == NULL) {
peer = oldCPU->getPort("dcache_port")->getPeer();
dc->setPeer(peer);
} else {
peer = dc->getPeer();
}
peer->setPeer(dc);
}

View File

@@ -196,7 +196,7 @@ class BaseCPU : public MemObject
/// Take over execution from the given CPU. Used for warm-up and
/// sampling.
virtual void takeOverFrom(BaseCPU *);
virtual void takeOverFrom(BaseCPU *, Port *ic, Port *dc);
/**
* Number of threads we're actually simulating (<= SMT_MAX_THREADS).

View File

@@ -557,12 +557,6 @@ template <class Impl>
void
FullO3CPU<Impl>::activateContext(int tid, int delay)
{
#if FULL_SYSTEM
// Connect the ThreadContext's memory ports (Functional/Virtual
// Ports)
threadContexts[tid]->connectMemPorts();
#endif
// Needs to set each stage to running as well.
if (delay){
DPRINTF(O3CPU, "[tid:%i]: Scheduling thread context to activate "
@@ -781,6 +775,18 @@ FullO3CPU<Impl>::activateWhenReady(int tid)
}
}
#if FULL_SYSTEM
template <class Impl>
void
FullO3CPU<Impl>::updateMemPorts()
{
// Update all ThreadContext's memory ports (Functional/Virtual
// Ports)
for (int i = 0; i < thread.size(); ++i)
thread[i]->connectMemPorts();
}
#endif
template <class Impl>
void
FullO3CPU<Impl>::serialize(std::ostream &os)
@@ -941,7 +947,7 @@ FullO3CPU<Impl>::takeOverFrom(BaseCPU *oldCPU)
activityRec.reset();
BaseCPU::takeOverFrom(oldCPU);
BaseCPU::takeOverFrom(oldCPU, fetch.getIcachePort(), iew.getDcachePort());
fetch.takeOverFrom();
decode.takeOverFrom();
@@ -978,25 +984,6 @@ FullO3CPU<Impl>::takeOverFrom(BaseCPU *oldCPU)
}
if (!tickEvent.scheduled())
tickEvent.schedule(curTick);
Port *peer;
Port *icachePort = fetch.getIcachePort();
if (icachePort->getPeer() == NULL) {
peer = oldCPU->getPort("icache_port")->getPeer();
icachePort->setPeer(peer);
} else {
peer = icachePort->getPeer();
}
peer->setPeer(icachePort);
Port *dcachePort = iew.getDcachePort();
if (dcachePort->getPeer() == NULL) {
peer = oldCPU->getPort("dcache_port")->getPeer();
dcachePort->setPeer(peer);
} else {
peer = dcachePort->getPeer();
}
peer->setPeer(dcachePort);
}
template <class Impl>

View File

@@ -357,6 +357,10 @@ class FullO3CPU : public BaseO3CPU
{ return globalSeqNum++; }
#if FULL_SYSTEM
/** Update the Virt and Phys ports of all ThreadContexts to
* reflect change in memory connections. */
void updateMemPorts();
/** Check if this address is a valid instruction address. */
bool validInstAddr(Addr addr) { return true; }

View File

@@ -300,6 +300,8 @@ class LSQ {
bool snoopRangeSent;
virtual void setPeer(Port *port);
protected:
/** Atomic version of receive. Panics. */
virtual Tick recvAtomic(PacketPtr pkt);
@@ -327,6 +329,11 @@ class LSQ {
/** D-cache port. */
DcachePort dcachePort;
#if FULL_SYSTEM
/** Tell the CPU to update the Phys and Virt ports. */
void updateMemPorts() { cpu->updateMemPorts(); }
#endif
protected:
/** The LSQ policy for SMT mode. */
LSQPolicy lsqPolicy;

View File

@@ -34,6 +34,19 @@
#include "cpu/o3/lsq.hh"
template<class Impl>
void
LSQ<Impl>::DcachePort::setPeer(Port *port)
{
Port::setPeer(port);
#if FULL_SYSTEM
// Update the ThreadContext's memory ports (Functional/Virtual
// Ports)
lsq->updateMemPorts();
#endif
}
template <class Impl>
Tick
LSQ<Impl>::DcachePort::recvAtomic(PacketPtr pkt)

View File

@@ -126,6 +126,17 @@ AtomicSimpleCPU::CpuPort::recvRetry()
panic("AtomicSimpleCPU doesn't expect recvRetry callback!");
}
void
AtomicSimpleCPU::DcachePort::setPeer(Port *port)
{
Port::setPeer(port);
#if FULL_SYSTEM
// Update the ThreadContext's memory ports (Functional/Virtual
// Ports)
cpu->tcBase()->connectMemPorts();
#endif
}
AtomicSimpleCPU::AtomicSimpleCPU(Params *p)
: BaseSimpleCPU(p), tickEvent(this),
@@ -211,7 +222,7 @@ AtomicSimpleCPU::switchOut()
void
AtomicSimpleCPU::takeOverFrom(BaseCPU *oldCPU)
{
BaseCPU::takeOverFrom(oldCPU);
BaseCPU::takeOverFrom(oldCPU, &icachePort, &dcachePort);
assert(!tickEvent.scheduled());
@@ -242,12 +253,6 @@ AtomicSimpleCPU::activateContext(int thread_num, int delay)
notIdleFraction++;
#if FULL_SYSTEM
// Connect the ThreadContext's memory ports (Functional/Virtual
// Ports)
tc->connectMemPorts();
#endif
//Make sure ticks are still on multiples of cycles
tickEvent.schedule(nextCycle(curTick + cycles(delay)));
_status = Running;

View File

@@ -81,9 +81,6 @@ class AtomicSimpleCPU : public BaseSimpleCPU
class CpuPort : public Port
{
AtomicSimpleCPU *cpu;
public:
CpuPort(const std::string &_name, AtomicSimpleCPU *_cpu)
@@ -94,6 +91,8 @@ class AtomicSimpleCPU : public BaseSimpleCPU
protected:
AtomicSimpleCPU *cpu;
virtual bool recvTiming(PacketPtr pkt);
virtual Tick recvAtomic(PacketPtr pkt);
@@ -110,7 +109,17 @@ class AtomicSimpleCPU : public BaseSimpleCPU
};
CpuPort icachePort;
CpuPort dcachePort;
class DcachePort : public CpuPort
{
public:
DcachePort(const std::string &_name, AtomicSimpleCPU *_cpu)
: CpuPort(_name, _cpu)
{ }
virtual void setPeer(Port *port);
};
DcachePort dcachePort;
Request *ifetch_req;
PacketPtr ifetch_pkt;

View File

@@ -194,7 +194,7 @@ TimingSimpleCPU::switchOut()
void
TimingSimpleCPU::takeOverFrom(BaseCPU *oldCPU)
{
BaseCPU::takeOverFrom(oldCPU);
BaseCPU::takeOverFrom(oldCPU, &icachePort, &dcachePort);
// if any of this CPU's ThreadContexts are active, mark the CPU as
// running and schedule its tick event.
@@ -209,23 +209,6 @@ TimingSimpleCPU::takeOverFrom(BaseCPU *oldCPU)
if (_status != Running) {
_status = Idle;
}
Port *peer;
if (icachePort.getPeer() == NULL) {
peer = oldCPU->getPort("icache_port")->getPeer();
icachePort.setPeer(peer);
} else {
peer = icachePort.getPeer();
}
peer->setPeer(&icachePort);
if (dcachePort.getPeer() == NULL) {
peer = oldCPU->getPort("dcache_port")->getPeer();
dcachePort.setPeer(peer);
} else {
peer = dcachePort.getPeer();
}
peer->setPeer(&dcachePort);
}
@@ -240,12 +223,6 @@ TimingSimpleCPU::activateContext(int thread_num, int delay)
notIdleFraction++;
_status = Running;
#if FULL_SYSTEM
// Connect the ThreadContext's memory ports (Functional/Virtual
// Ports)
tc->connectMemPorts();
#endif
// kick things off by initiating the fetch of the next instruction
fetchEvent =
new EventWrapper<TimingSimpleCPU, &TimingSimpleCPU::fetch>(this, false);
@@ -649,6 +626,18 @@ TimingSimpleCPU::completeDrain()
drainEvent->process();
}
void
TimingSimpleCPU::DcachePort::setPeer(Port *port)
{
Port::setPeer(port);
#if FULL_SYSTEM
// Update the ThreadContext's memory ports (Functional/Virtual
// Ports)
cpu->tcBase()->connectMemPorts();
#endif
}
bool
TimingSimpleCPU::DcachePort::recvTiming(PacketPtr pkt)
{

View File

@@ -144,6 +144,8 @@ class TimingSimpleCPU : public BaseSimpleCPU
: CpuPort(_cpu->name() + "-dport", _cpu, _lat), tickEvent(_cpu)
{ }
virtual void setPeer(Port *port);
protected:
virtual bool recvTiming(PacketPtr pkt);

View File

@@ -120,7 +120,7 @@ class Port
{ portName = name; }
/** Function to set the pointer for the peer port. */
void setPeer(Port *port);
virtual void setPeer(Port *port);
/** Function to get the pointer to the peer port. */
Port *getPeer() { return peer; }