/*
+ * Copyright (c) 2011 ARM Limited
+ * All rights reserved.
+ *
+ * The license below extends only to copyright in the software and shall
+ * not be construed as granting a license to any other intellectual
+ * property including but not limited to intellectual property relating
+ * to a hardware implementation of the functionality of the software
+ * licensed hereunder. You may use the software subject to the license
+ * terms below provided that you ensure that this notice is replicated
+ * unmodified and in its entirety in all distributions of the software,
+ * modified or unmodified, in source code or in binary form.
+ *
* Copyright (c) 2002-2005 The Regents of The University of Michigan
* Copyright (c) 2009 The University of Edinburgh
* All rights reserved.
#ifndef __CPU_TRANSLATION_HH__
#define __CPU_TRANSLATION_HH__
+#include "sim/faults.hh"
#include "sim/tlb.hh"
+/**
+ * This class captures the state of an address translation. A translation
+ * can be split in two if the ISA supports it and the memory access crosses
+ * a page boundary. In this case, this class is shared by two data
+ * translations (below). Otherwise it is used by a single data translation
+ * class. When each part of the translation is finished, the finish
+ * function is called which will indicate whether the whole translation is
+ * completed or not. There are also functions for accessing parts of the
+ * translation state which deal with the possible split correctly.
+ */
class WholeTranslationState
{
protected:
Fault faults[2];
public:
+ bool delay;
bool isSplit;
RequestPtr mainReq;
RequestPtr sreqLow;
uint64_t *res;
BaseTLB::Mode mode;
- /** Single translation state. */
+ /**
+ * Single translation state. We set the number of outstanding
+ * translations to one and indicate that it is not split.
+ */
WholeTranslationState(RequestPtr _req, uint8_t *_data, uint64_t *_res,
BaseTLB::Mode _mode)
- : outstanding(1), isSplit(false), mainReq(_req), sreqLow(NULL),
- sreqHigh(NULL), data(_data), res(_res), mode(_mode)
+ : outstanding(1), delay(false), isSplit(false), mainReq(_req),
+ sreqLow(NULL), sreqHigh(NULL), data(_data), res(_res), mode(_mode)
{
faults[0] = faults[1] = NoFault;
assert(mode == BaseTLB::Read || mode == BaseTLB::Write);
}
- /** Split translation state. */
+ /**
+ * Split translation state. We copy all state into this class, set the
+ * number of outstanding translations to two and then mark this as a
+ * split translation.
+ */
WholeTranslationState(RequestPtr _req, RequestPtr _sreqLow,
RequestPtr _sreqHigh, uint8_t *_data, uint64_t *_res,
BaseTLB::Mode _mode)
- : outstanding(2), isSplit(true), mainReq(_req), sreqLow(_sreqLow),
- sreqHigh(_sreqHigh), data(_data), res(_res), mode(_mode)
+ : outstanding(2), delay(false), isSplit(true), mainReq(_req),
+ sreqLow(_sreqLow), sreqHigh(_sreqHigh), data(_data), res(_res),
+ mode(_mode)
{
faults[0] = faults[1] = NoFault;
assert(mode == BaseTLB::Read || mode == BaseTLB::Write);
}
+ /**
+ * Finish part of a translation. If there is only one request then this
+ * translation is completed. If the request has been split in two then
+ * the outstanding count determines whether the translation is complete.
+ * In this case, flags from the split request are copied to the main
+ * request to make it easier to access them later on.
+ */
bool
finish(Fault fault, int index)
{
return outstanding == 0;
}
+ /**
+ * Determine whether this translation produced a fault. Both parts of the
+ * translation must be checked if this is a split translation.
+ */
Fault
getFault() const
{
return NoFault;
}
+ /** Remove all faults from the translation. */
void
setNoFault()
{
faults[0] = faults[1] = NoFault;
}
+ /**
+ * Check if this request is uncacheable. We only need to check the main
+ * request because the flags will have been copied here on a split
+ * translation.
+ */
bool
isUncacheable() const
{
return mainReq->isUncacheable();
}
+ /**
+ * Check if this request is a prefetch. We only need to check the main
+ * request because the flags will have been copied here on a split
+ * translation.
+ */
bool
isPrefetch() const
{
return mainReq->isPrefetch();
}
+ /** Get the physical address of this request. */
Addr
getPaddr() const
{
return mainReq->getPaddr();
}
+ /**
+ * Get the flags associated with this request. We only need to access
+ * the main request because the flags will have been copied here on a
+ * split translation.
+ */
unsigned
getFlags()
{
return mainReq->getFlags();
}
+ /** Delete all requests that make up this translation. */
void
deleteReqs()
{
}
};
-template <class ExecContext>
+
+/**
+ * This class represents part of a data address translation. All state for
+ * the translation is held in WholeTranslationState (above). Therefore this
+ * class does not need to know whether the translation is split or not. The
+ * index variable determines this but is simply passed on to the state class.
+ * When this part of the translation is completed, finish is called. If the
+ * translation state class indicate that the whole translation is complete
+ * then the execution context is informed.
+ */
+template <class ExecContextPtr>
class DataTranslation : public BaseTLB::Translation
{
protected:
- ExecContext *xc;
+ ExecContextPtr xc;
WholeTranslationState *state;
int index;
public:
- DataTranslation(ExecContext *_xc, WholeTranslationState* _state)
+ DataTranslation(ExecContextPtr _xc, WholeTranslationState* _state)
: xc(_xc), state(_state), index(0)
{
}
- DataTranslation(ExecContext *_xc, WholeTranslationState* _state,
+ DataTranslation(ExecContextPtr _xc, WholeTranslationState* _state,
int _index)
: xc(_xc), state(_state), index(_index)
{
}
+ /**
+ * Signal the translation state that the translation has been delayed due
+ * to a hw page table walk. Split requests are transparently handled.
+ */
+ void
+ markDelayed()
+ {
+ state->delay = true;
+ }
+
+ /**
+ * Finish this part of the translation and indicate that the whole
+ * translation is complete if the state says so.
+ */
void
finish(Fault fault, RequestPtr req, ThreadContext *tc,
BaseTLB::Mode mode)