gem5/src/cpu/simple/timing.hh
Andreas Hansson 0cacf7e817 Clock: Add a Cycles wrapper class and use where applicable
This patch addresses the comments and feedback on the preceding patch
that reworks the clocks and now more clearly shows where cycles
(relative cycle counts) are used to express time.

Instead of bumping the existing patch I chose to make this a separate
patch, merely to try and focus the discussion around a smaller set of
changes. The two patches will be pushed together though.

This changes done as part of this patch are mostly following directly
from the introduction of the wrapper class, and change enough code to
make things compile and run again. There are definitely more places
where int/uint/Tick is still used to represent cycles, and it will
take some time to chase them all down. Similarly, a lot of parameters
should be changed from Param.Tick and Param.Unsigned to
Param.Cycles.

In addition, the use of curTick is questionable as there should not be
an absolute cycle. Potential solutions can be built on top of this
patch. There is a similar situation in the o3 CPU where
lastRunningCycle is currently counting in Cycles, and is still an
absolute time. More discussion to be had in other words.

An additional change that would be appropriate in the future is to
perform a similar wrapping of Tick and probably also introduce a
Ticks class along with suitable operators for all these classes.
2012-08-28 14:30:33 -04:00

301 lines
8.6 KiB
C++

/*
* Copyright (c) 2002-2005 The Regents of The University of Michigan
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met: redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer;
* redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution;
* neither the name of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Authors: Steve Reinhardt
*/
#ifndef __CPU_SIMPLE_TIMING_HH__
#define __CPU_SIMPLE_TIMING_HH__
#include "cpu/simple/base.hh"
#include "cpu/translation.hh"
#include "params/TimingSimpleCPU.hh"
class TimingSimpleCPU : public BaseSimpleCPU
{
public:
TimingSimpleCPU(TimingSimpleCPUParams * params);
virtual ~TimingSimpleCPU();
virtual void init();
public:
Event *drainEvent;
private:
/*
* If an access needs to be broken into fragments, currently at most two,
* the the following two classes are used as the sender state of the
* packets so the CPU can keep track of everything. In the main packet
* sender state, there's an array with a spot for each fragment. If a
* fragment has already been accepted by the CPU, aka isn't waiting for
* a retry, it's pointer is NULL. After each fragment has successfully
* been processed, the "outstanding" counter is decremented. Once the
* count is zero, the entire larger access is complete.
*/
class SplitMainSenderState : public Packet::SenderState
{
public:
int outstanding;
PacketPtr fragments[2];
int
getPendingFragment()
{
if (fragments[0]) {
return 0;
} else if (fragments[1]) {
return 1;
} else {
return -1;
}
}
};
class SplitFragmentSenderState : public Packet::SenderState
{
public:
SplitFragmentSenderState(PacketPtr _bigPkt, int _index) :
bigPkt(_bigPkt), index(_index)
{}
PacketPtr bigPkt;
int index;
void
clearFromParent()
{
SplitMainSenderState * main_send_state =
dynamic_cast<SplitMainSenderState *>(bigPkt->senderState);
main_send_state->fragments[index] = NULL;
}
};
class FetchTranslation : public BaseTLB::Translation
{
protected:
TimingSimpleCPU *cpu;
public:
FetchTranslation(TimingSimpleCPU *_cpu)
: cpu(_cpu)
{}
void
markDelayed()
{
assert(cpu->_status == Running);
cpu->_status = ITBWaitResponse;
}
void
finish(Fault fault, RequestPtr req, ThreadContext *tc,
BaseTLB::Mode mode)
{
cpu->sendFetch(fault, req, tc);
}
};
FetchTranslation fetchTranslation;
void sendData(RequestPtr req, uint8_t *data, uint64_t *res, bool read);
void sendSplitData(RequestPtr req1, RequestPtr req2, RequestPtr req,
uint8_t *data, bool read);
void translationFault(Fault fault);
void buildPacket(PacketPtr &pkt, RequestPtr req, bool read);
void buildSplitPacket(PacketPtr &pkt1, PacketPtr &pkt2,
RequestPtr req1, RequestPtr req2, RequestPtr req,
uint8_t *data, bool read);
bool handleReadPacket(PacketPtr pkt);
// This function always implicitly uses dcache_pkt.
bool handleWritePacket();
/**
* A TimingCPUPort overrides the default behaviour of the
* recvTiming and recvRetry and implements events for the
* scheduling of handling of incoming packets in the following
* cycle.
*/
class TimingCPUPort : public CpuPort
{
public:
TimingCPUPort(const std::string& _name, TimingSimpleCPU* _cpu)
: CpuPort(_name, _cpu), cpu(_cpu), retryEvent(this)
{ }
protected:
/**
* Snooping a coherence request, do nothing.
*/
virtual void recvTimingSnoopReq(PacketPtr pkt) { }
TimingSimpleCPU* cpu;
struct TickEvent : public Event
{
PacketPtr pkt;
TimingSimpleCPU *cpu;
TickEvent(TimingSimpleCPU *_cpu) : pkt(NULL), cpu(_cpu) {}
const char *description() const { return "Timing CPU tick"; }
void schedule(PacketPtr _pkt, Tick t);
};
EventWrapper<MasterPort, &MasterPort::sendRetry> retryEvent;
};
class IcachePort : public TimingCPUPort
{
public:
IcachePort(TimingSimpleCPU *_cpu)
: TimingCPUPort(_cpu->name() + ".icache_port", _cpu),
tickEvent(_cpu)
{ }
protected:
virtual bool recvTimingResp(PacketPtr pkt);
virtual void recvRetry();
struct ITickEvent : public TickEvent
{
ITickEvent(TimingSimpleCPU *_cpu)
: TickEvent(_cpu) {}
void process();
const char *description() const { return "Timing CPU icache tick"; }
};
ITickEvent tickEvent;
};
class DcachePort : public TimingCPUPort
{
public:
DcachePort(TimingSimpleCPU *_cpu)
: TimingCPUPort(_cpu->name() + ".dcache_port", _cpu),
tickEvent(_cpu)
{ }
protected:
virtual bool recvTimingResp(PacketPtr pkt);
virtual void recvRetry();
struct DTickEvent : public TickEvent
{
DTickEvent(TimingSimpleCPU *_cpu)
: TickEvent(_cpu) {}
void process();
const char *description() const { return "Timing CPU dcache tick"; }
};
DTickEvent tickEvent;
};
IcachePort icachePort;
DcachePort dcachePort;
PacketPtr ifetch_pkt;
PacketPtr dcache_pkt;
Tick previousCycle;
protected:
/** Return a reference to the data port. */
virtual CpuPort &getDataPort() { return dcachePort; }
/** Return a reference to the instruction port. */
virtual CpuPort &getInstPort() { return icachePort; }
public:
virtual void serialize(std::ostream &os);
virtual void unserialize(Checkpoint *cp, const std::string &section);
virtual unsigned int drain(Event *drain_event);
virtual void resume();
void switchOut();
void takeOverFrom(BaseCPU *oldCPU);
virtual void activateContext(ThreadID thread_num, Cycles delay);
virtual void suspendContext(ThreadID thread_num);
Fault readMem(Addr addr, uint8_t *data, unsigned size, unsigned flags);
Fault writeMem(uint8_t *data, unsigned size,
Addr addr, unsigned flags, uint64_t *res);
void fetch();
void sendFetch(Fault fault, RequestPtr req, ThreadContext *tc);
void completeIfetch(PacketPtr );
void completeDataAccess(PacketPtr pkt);
void advanceInst(Fault fault);
/**
* Print state of address in memory system via PrintReq (for
* debugging).
*/
void printAddr(Addr a);
/**
* Finish a DTB translation.
* @param state The DTB translation state.
*/
void finishTranslation(WholeTranslationState *state);
private:
typedef EventWrapper<TimingSimpleCPU, &TimingSimpleCPU::fetch> FetchEvent;
FetchEvent fetchEvent;
struct IprEvent : Event {
Packet *pkt;
TimingSimpleCPU *cpu;
IprEvent(Packet *_pkt, TimingSimpleCPU *_cpu, Tick t);
virtual void process();
virtual const char *description() const;
};
void completeDrain();
};
#endif // __CPU_SIMPLE_TIMING_HH__