#include "base/compiler.hh"
#include "base/fast_alloc.hh"
#include "base/misc.hh"
+#include "base/printable.hh"
#include "mem/request.hh"
#include "sim/host.hh"
#include "sim/core.hh"
InvalidCmd,
ReadReq,
ReadResp,
+ ReadRespWithInvalidate,
WriteReq,
WriteResp,
Writeback,
ReadExReq,
ReadExResp,
LoadLockedReq,
- LoadLockedResp,
StoreCondReq,
StoreCondResp,
SwapReq,
NetworkNackError, // nacked at network layer (not by protocol)
InvalidDestError, // packet dest field invalid
BadAddressError, // memory address invalid
+ // Fake simulator-only commands
+ PrintReq, // Print state matching address
NUM_MEM_CMDS
};
IsLocked, //!< Alpha/MIPS LL or SC access
HasData, //!< There is an associated payload
IsError, //!< Error response
+ IsPrint, //!< Print state matching address (for debugging)
NUM_COMMAND_ATTRIBUTES
};
bool isReadWrite() const { return isRead() && isWrite(); }
bool isLocked() const { return testCmdAttrib(IsLocked); }
bool isError() const { return testCmdAttrib(IsError); }
+ bool isPrint() const { return testCmdAttrib(IsPrint); }
const Command responseCommand() const {
return commandInfo[cmd].response;
* ultimate destination and back, possibly being conveyed by several
* different Packets along the way.)
*/
-class Packet : public FastAlloc
+class Packet : public FastAlloc, public Printable
{
public:
bool destValid;
enum Flag {
- // Snoop flags
+ // Snoop response flags
MemInhibit,
Shared,
+ // Special control flags
+ /// Special timing-mode atomic snoop for multi-level coherence.
+ ExpressSnoop,
+ /// Does supplier have exclusive copy?
+ /// Useful for multi-level coherence.
+ SupplyExclusive,
NUM_PACKET_FLAGS
};
* needed to process it. A specific subclass would be derived
* from this to carry state specific to a particular sending
* device. */
- class SenderState : public FastAlloc {
+ class SenderState {
public:
virtual ~SenderState() {}
};
+ /**
+ * Object used to maintain state of a PrintReq. The senderState
+ * field of a PrintReq should always be of this type.
+ */
+ class PrintReqState : public SenderState, public FastAlloc {
+ /** An entry in the label stack. */
+ class LabelStackEntry {
+ public:
+ const std::string label;
+ std::string *prefix;
+ bool labelPrinted;
+ LabelStackEntry(const std::string &_label,
+ std::string *_prefix);
+ };
+
+ typedef std::list<LabelStackEntry> LabelStack;
+ LabelStack labelStack;
+
+ std::string *curPrefixPtr;
+
+ public:
+ std::ostream &os;
+ const int verbosity;
+
+ PrintReqState(std::ostream &os, int verbosity = 0);
+ ~PrintReqState();
+
+ /** Returns the current line prefix. */
+ const std::string &curPrefix() { return *curPrefixPtr; }
+
+ /** Push a label onto the label stack, and prepend the given
+ * prefix string onto the current prefix. Labels will only be
+ * printed if an object within the label's scope is
+ * printed. */
+ void pushLabel(const std::string &lbl,
+ const std::string &prefix = " ");
+ /** Pop a label off the label stack. */
+ void popLabel();
+ /** Print all of the pending unprinted labels on the
+ * stack. Called by printObj(), so normally not called by
+ * users unless bypassing printObj(). */
+ void printLabels();
+ /** Print a Printable object to os, because it matched the
+ * address on a PrintReq. */
+ void printObj(Printable *obj);
+ };
+
/** This packet's sender state. Devices should use dynamic_cast<>
* to cast to the state appropriate to the sender. */
SenderState *senderState;
bool isReadWrite() const { return cmd.isReadWrite(); }
bool isLocked() const { return cmd.isLocked(); }
bool isError() const { return cmd.isError(); }
+ bool isPrint() const { return cmd.isPrint(); }
// Snoop flags
void assertMemInhibit() { flags[MemInhibit] = true; }
- void assertShared() { flags[Shared] = true; }
bool memInhibitAsserted() { return flags[MemInhibit]; }
+ void assertShared() { flags[Shared] = true; }
bool sharedAsserted() { return flags[Shared]; }
+ // Special control flags
+ void setExpressSnoop() { flags[ExpressSnoop] = true; }
+ bool isExpressSnoop() { return flags[ExpressSnoop]; }
+ void setSupplyExclusive() { flags[SupplyExclusive] = true; }
+ bool isSupplyExclusive() { return flags[SupplyExclusive]; }
+
// Network error conditions... encapsulate them as methods since
// their encoding keeps changing (from result field to command
// field, etc.)
- void setNacked() { origCmd = cmd; cmd = MemCmd::NetworkNackError; }
- void setBadAddress() { origCmd = cmd; cmd = MemCmd::BadAddressError; }
+ void setNacked() { assert(isResponse()); cmd = MemCmd::NetworkNackError; }
+ void setBadAddress() { assert(isResponse()); cmd = MemCmd::BadAddressError; }
bool wasNacked() { return cmd == MemCmd::NetworkNackError; }
bool hadBadAddress() { return cmd == MemCmd::BadAddressError; }
+ void copyError(Packet *pkt) { assert(pkt->isError()); cmd = pkt->cmd; }
bool nic_pkt() { panic("Unimplemented"); M5_DUMMY_RETURN }
* that, as we can't guarantee that the new packet's lifetime is
* less than that of the original packet. In this case the new
* packet should allocate its own data. */
- Packet(Packet *origPkt)
+ Packet(Packet *origPkt, bool clearFlags = false)
: cmd(origPkt->cmd), req(origPkt->req),
data(origPkt->staticData ? origPkt->data : NULL),
staticData(origPkt->staticData),
src(origPkt->src), dest(origPkt->dest),
addrSizeValid(origPkt->addrSizeValid),
srcValid(origPkt->srcValid), destValid(origPkt->destValid),
- flags(origPkt->flags),
+ flags(clearFlags ? 0 : origPkt->flags),
time(curTick), senderState(origPkt->senderState)
{
}
/** Destructor. */
~Packet()
- { if (staticData || dynamicData) deleteData(); }
+ {
+ // If this is a request packet for which there's no response,
+ // delete the request object here, since the requester will
+ // never get the chance.
+ if (req && isRequest() && !needsResponse())
+ delete req;
+ if (staticData || dynamicData)
+ deleteData();
+ }
/** Reinitialize packet address and size from the associated
* Request object, and reset other fields that may have been
{
assert(needsResponse());
assert(isRequest());
+ origCmd = cmd;
cmd = cmd.responseCommand();
dest = src;
destValid = srcValid;
/** If there isn't data in the packet, allocate some. */
void allocate();
- /** Do the packet modify the same addresses. */
- bool intersect(PacketPtr p);
-
/**
* Check a functional request against a memory value represented
* by a base/size pair and an associated data array. If the
* value. If the functional request is a write, it may update the
* memory value.
*/
- bool checkFunctional(Addr base, int size, uint8_t *data);
+ bool checkFunctional(Printable *obj, Addr base, int size, uint8_t *data);
/**
* Check a functional request against a memory value stored in
* another packet (i.e. an in-transit request or response).
*/
bool checkFunctional(PacketPtr otherPkt) {
- return (otherPkt->hasData() &&
- checkFunctional(otherPkt->getAddr(), otherPkt->getSize(),
- otherPkt->getPtr<uint8_t>()));
+ return checkFunctional(otherPkt,
+ otherPkt->getAddr(), otherPkt->getSize(),
+ otherPkt->hasData() ?
+ otherPkt->getPtr<uint8_t>() : NULL);
+ }
+
+ /**
+ * Push label for PrintReq (safe to call unconditionally).
+ */
+ void pushLabel(const std::string &lbl) {
+ if (isPrint()) {
+ dynamic_cast<PrintReqState*>(senderState)->pushLabel(lbl);
+ }
}
-};
-std::ostream & operator<<(std::ostream &o, const Packet &p);
+ /**
+ * Pop label for PrintReq (safe to call unconditionally).
+ */
+ void popLabel() {
+ if (isPrint()) {
+ dynamic_cast<PrintReqState*>(senderState)->popLabel();
+ }
+ }
+
+ void print(std::ostream &o, int verbosity = 0,
+ const std::string &prefix = "") const;
+};
#endif //__MEM_PACKET_HH