Mem: Make errors in the memory system be responses, not requests. Fixes cache handling of error responses.
--HG-- extra : convert_revision : 22309fc61bd1be0f8d31a3926f290290789a37e5
This commit is contained in:
parent
e1054170b5
commit
4e89518817
13 changed files with 69 additions and 35 deletions
|
@ -364,6 +364,8 @@ DefaultFetch<Impl>::processCacheCompletion(PacketPtr pkt)
|
||||||
|
|
||||||
DPRINTF(Fetch, "[tid:%u] Waking up from cache miss.\n",tid);
|
DPRINTF(Fetch, "[tid:%u] Waking up from cache miss.\n",tid);
|
||||||
|
|
||||||
|
assert(!pkt->wasNacked());
|
||||||
|
|
||||||
// Only change the status if it's still waiting on the icache access
|
// Only change the status if it's still waiting on the icache access
|
||||||
// to return.
|
// to return.
|
||||||
if (fetchStatus[tid] != IcacheWaitResponse ||
|
if (fetchStatus[tid] != IcacheWaitResponse ||
|
||||||
|
|
|
@ -80,6 +80,8 @@ template <class Impl>
|
||||||
bool
|
bool
|
||||||
LSQ<Impl>::DcachePort::recvTiming(PacketPtr pkt)
|
LSQ<Impl>::DcachePort::recvTiming(PacketPtr pkt)
|
||||||
{
|
{
|
||||||
|
if (pkt->isError())
|
||||||
|
DPRINTF(LSQ, "Got error packet back for address: %#X\n", pkt->getAddr());
|
||||||
if (pkt->isResponse()) {
|
if (pkt->isResponse()) {
|
||||||
lsq->thread[pkt->req->getThreadNum()].completeDataAccess(pkt);
|
lsq->thread[pkt->req->getThreadNum()].completeDataAccess(pkt);
|
||||||
}
|
}
|
||||||
|
|
|
@ -83,6 +83,8 @@ LSQUnit<Impl>::completeDataAccess(PacketPtr pkt)
|
||||||
|
|
||||||
//iewStage->ldstQueue.removeMSHR(inst->threadNumber,inst->seqNum);
|
//iewStage->ldstQueue.removeMSHR(inst->threadNumber,inst->seqNum);
|
||||||
|
|
||||||
|
assert(!pkt->wasNacked());
|
||||||
|
|
||||||
if (isSwitchedOut() || inst->isSquashed()) {
|
if (isSwitchedOut() || inst->isSquashed()) {
|
||||||
iewStage->decrWb(inst->seqNum);
|
iewStage->decrWb(inst->seqNum);
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -311,6 +311,7 @@ AtomicSimpleCPU::read(Addr addr, T &data, unsigned flags)
|
||||||
dcache_latency = dcachePort.sendAtomic(&pkt);
|
dcache_latency = dcachePort.sendAtomic(&pkt);
|
||||||
}
|
}
|
||||||
dcache_access = true;
|
dcache_access = true;
|
||||||
|
|
||||||
assert(!pkt.isError());
|
assert(!pkt.isError());
|
||||||
|
|
||||||
data = gtoh(data);
|
data = gtoh(data);
|
||||||
|
@ -536,6 +537,7 @@ AtomicSimpleCPU::tick()
|
||||||
else
|
else
|
||||||
icache_latency = icachePort.sendAtomic(&ifetch_pkt);
|
icache_latency = icachePort.sendAtomic(&ifetch_pkt);
|
||||||
|
|
||||||
|
assert(!ifetch_pkt.isError());
|
||||||
|
|
||||||
// ifetch_req is initialized to read the instruction directly
|
// ifetch_req is initialized to read the instruction directly
|
||||||
// into the CPU object's inst field.
|
// into the CPU object's inst field.
|
||||||
|
|
|
@ -564,7 +564,7 @@ TimingSimpleCPU::IcachePort::ITickEvent::process()
|
||||||
bool
|
bool
|
||||||
TimingSimpleCPU::IcachePort::recvTiming(PacketPtr pkt)
|
TimingSimpleCPU::IcachePort::recvTiming(PacketPtr pkt)
|
||||||
{
|
{
|
||||||
if (pkt->isResponse()) {
|
if (pkt->isResponse() && !pkt->wasNacked()) {
|
||||||
// delay processing of returned data until next CPU clock edge
|
// delay processing of returned data until next CPU clock edge
|
||||||
Tick next_tick = cpu->nextCycle(curTick);
|
Tick next_tick = cpu->nextCycle(curTick);
|
||||||
|
|
||||||
|
@ -658,7 +658,7 @@ TimingSimpleCPU::DcachePort::setPeer(Port *port)
|
||||||
bool
|
bool
|
||||||
TimingSimpleCPU::DcachePort::recvTiming(PacketPtr pkt)
|
TimingSimpleCPU::DcachePort::recvTiming(PacketPtr pkt)
|
||||||
{
|
{
|
||||||
if (pkt->isResponse()) {
|
if (pkt->isResponse() && !pkt->wasNacked()) {
|
||||||
// delay processing of returned data until next CPU clock edge
|
// delay processing of returned data until next CPU clock edge
|
||||||
Tick next_tick = cpu->nextCycle(curTick);
|
Tick next_tick = cpu->nextCycle(curTick);
|
||||||
|
|
||||||
|
|
|
@ -107,6 +107,7 @@ AlphaConsole::read(PacketPtr pkt)
|
||||||
Addr daddr = pkt->getAddr() - pioAddr;
|
Addr daddr = pkt->getAddr() - pioAddr;
|
||||||
|
|
||||||
pkt->allocate();
|
pkt->allocate();
|
||||||
|
pkt->makeAtomicResponse();
|
||||||
|
|
||||||
switch (pkt->getSize())
|
switch (pkt->getSize())
|
||||||
{
|
{
|
||||||
|
@ -188,7 +189,6 @@ AlphaConsole::read(PacketPtr pkt)
|
||||||
default:
|
default:
|
||||||
pkt->setBadAddress();
|
pkt->setBadAddress();
|
||||||
}
|
}
|
||||||
pkt->makeAtomicResponse();
|
|
||||||
return pioDelay;
|
return pioDelay;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -56,6 +56,7 @@ Tick
|
||||||
IsaFake::read(PacketPtr pkt)
|
IsaFake::read(PacketPtr pkt)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
pkt->makeAtomicResponse();
|
||||||
if (params()->warn_access != "")
|
if (params()->warn_access != "")
|
||||||
warn("Device %s accessed by read to address %#x size=%d\n",
|
warn("Device %s accessed by read to address %#x size=%d\n",
|
||||||
name(), pkt->getAddr(), pkt->getSize());
|
name(), pkt->getAddr(), pkt->getSize());
|
||||||
|
@ -83,7 +84,6 @@ IsaFake::read(PacketPtr pkt)
|
||||||
default:
|
default:
|
||||||
panic("invalid access size!\n");
|
panic("invalid access size!\n");
|
||||||
}
|
}
|
||||||
pkt->makeAtomicResponse();
|
|
||||||
}
|
}
|
||||||
return pioDelay;
|
return pioDelay;
|
||||||
}
|
}
|
||||||
|
@ -91,6 +91,7 @@ IsaFake::read(PacketPtr pkt)
|
||||||
Tick
|
Tick
|
||||||
IsaFake::write(PacketPtr pkt)
|
IsaFake::write(PacketPtr pkt)
|
||||||
{
|
{
|
||||||
|
pkt->makeAtomicResponse();
|
||||||
if (params()->warn_access != "") {
|
if (params()->warn_access != "") {
|
||||||
uint64_t data;
|
uint64_t data;
|
||||||
switch (pkt->getSize()) {
|
switch (pkt->getSize()) {
|
||||||
|
@ -138,7 +139,6 @@ IsaFake::write(PacketPtr pkt)
|
||||||
panic("invalid access size!\n");
|
panic("invalid access size!\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pkt->makeAtomicResponse();
|
|
||||||
}
|
}
|
||||||
return pioDelay;
|
return pioDelay;
|
||||||
}
|
}
|
||||||
|
|
|
@ -119,17 +119,17 @@ Bridge::BridgePort::recvTiming(PacketPtr pkt)
|
||||||
|
|
||||||
DPRINTF(BusBridge, "Local queue size: %d outreq: %d outresp: %d\n",
|
DPRINTF(BusBridge, "Local queue size: %d outreq: %d outresp: %d\n",
|
||||||
sendQueue.size(), queuedRequests, outstandingResponses);
|
sendQueue.size(), queuedRequests, outstandingResponses);
|
||||||
DPRINTF(BusBridge, "Remove queue size: %d outreq: %d outresp: %d\n",
|
DPRINTF(BusBridge, "Remote queue size: %d outreq: %d outresp: %d\n",
|
||||||
otherPort->sendQueue.size(), otherPort->queuedRequests,
|
otherPort->sendQueue.size(), otherPort->queuedRequests,
|
||||||
otherPort->outstandingResponses);
|
otherPort->outstandingResponses);
|
||||||
|
|
||||||
if (pkt->isRequest() && otherPort->reqQueueFull() && !pkt->wasNacked()) {
|
if (pkt->isRequest() && otherPort->reqQueueFull()) {
|
||||||
DPRINTF(BusBridge, "Remote queue full, nacking\n");
|
DPRINTF(BusBridge, "Remote queue full, nacking\n");
|
||||||
nackRequest(pkt);
|
nackRequest(pkt);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pkt->needsResponse() && !pkt->wasNacked())
|
if (pkt->needsResponse())
|
||||||
if (respQueueFull()) {
|
if (respQueueFull()) {
|
||||||
DPRINTF(BusBridge, "Local queue full, no space for response, nacking\n");
|
DPRINTF(BusBridge, "Local queue full, no space for response, nacking\n");
|
||||||
DPRINTF(BusBridge, "queue size: %d outreq: %d outstanding resp: %d\n",
|
DPRINTF(BusBridge, "queue size: %d outreq: %d outstanding resp: %d\n",
|
||||||
|
@ -150,8 +150,8 @@ void
|
||||||
Bridge::BridgePort::nackRequest(PacketPtr pkt)
|
Bridge::BridgePort::nackRequest(PacketPtr pkt)
|
||||||
{
|
{
|
||||||
// Nack the packet
|
// Nack the packet
|
||||||
|
pkt->makeTimingResponse();
|
||||||
pkt->setNacked();
|
pkt->setNacked();
|
||||||
pkt->setDest(pkt->getSrc());
|
|
||||||
|
|
||||||
//put it on the list to send
|
//put it on the list to send
|
||||||
Tick readyTime = curTick + nackDelay;
|
Tick readyTime = curTick + nackDelay;
|
||||||
|
@ -195,27 +195,23 @@ Bridge::BridgePort::nackRequest(PacketPtr pkt)
|
||||||
void
|
void
|
||||||
Bridge::BridgePort::queueForSendTiming(PacketPtr pkt)
|
Bridge::BridgePort::queueForSendTiming(PacketPtr pkt)
|
||||||
{
|
{
|
||||||
if (pkt->isResponse() || pkt->wasNacked()) {
|
if (pkt->isResponse()) {
|
||||||
// This is a response for a request we forwarded earlier. The
|
// This is a response for a request we forwarded earlier. The
|
||||||
// corresponding PacketBuffer should be stored in the packet's
|
// corresponding PacketBuffer should be stored in the packet's
|
||||||
// senderState field.
|
// senderState field.
|
||||||
|
|
||||||
PacketBuffer *buf = dynamic_cast<PacketBuffer*>(pkt->senderState);
|
PacketBuffer *buf = dynamic_cast<PacketBuffer*>(pkt->senderState);
|
||||||
assert(buf != NULL);
|
assert(buf != NULL);
|
||||||
// set up new packet dest & senderState based on values saved
|
// set up new packet dest & senderState based on values saved
|
||||||
// from original request
|
// from original request
|
||||||
buf->fixResponse(pkt);
|
buf->fixResponse(pkt);
|
||||||
|
|
||||||
// Check if this packet was expecting a response and it's a nacked
|
|
||||||
// packet, in which case we will never being seeing it
|
|
||||||
if (buf->expectResponse && pkt->wasNacked())
|
|
||||||
--outstandingResponses;
|
|
||||||
|
|
||||||
DPRINTF(BusBridge, "response, new dest %d\n", pkt->getDest());
|
DPRINTF(BusBridge, "response, new dest %d\n", pkt->getDest());
|
||||||
delete buf;
|
delete buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (pkt->isRequest() && !pkt->wasNacked()) {
|
if (pkt->isRequest()) {
|
||||||
++queuedRequests;
|
++queuedRequests;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -249,7 +245,15 @@ Bridge::BridgePort::trySend()
|
||||||
buf->origSrc, pkt->getDest(), pkt->getAddr());
|
buf->origSrc, pkt->getDest(), pkt->getAddr());
|
||||||
|
|
||||||
bool wasReq = pkt->isRequest();
|
bool wasReq = pkt->isRequest();
|
||||||
bool wasNacked = pkt->wasNacked();
|
bool was_nacked_here = buf->nackedHere;
|
||||||
|
|
||||||
|
// If the send was successful, make sure sender state was set to NULL
|
||||||
|
// otherwise we could get a NACK back of a packet that didn't expect a
|
||||||
|
// response and we would try to use freed memory.
|
||||||
|
|
||||||
|
Packet::SenderState *old_sender_state = pkt->senderState;
|
||||||
|
if (pkt->isRequest() && !buf->expectResponse)
|
||||||
|
pkt->senderState = NULL;
|
||||||
|
|
||||||
if (sendTiming(pkt)) {
|
if (sendTiming(pkt)) {
|
||||||
// send successful
|
// send successful
|
||||||
|
@ -266,12 +270,10 @@ Bridge::BridgePort::trySend()
|
||||||
delete buf;
|
delete buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!wasNacked) {
|
|
||||||
if (wasReq)
|
if (wasReq)
|
||||||
--queuedRequests;
|
--queuedRequests;
|
||||||
else
|
else if (!was_nacked_here)
|
||||||
--outstandingResponses;
|
--outstandingResponses;
|
||||||
}
|
|
||||||
|
|
||||||
// If there are more packets to send, schedule event to try again.
|
// If there are more packets to send, schedule event to try again.
|
||||||
if (!sendQueue.empty()) {
|
if (!sendQueue.empty()) {
|
||||||
|
@ -281,8 +283,10 @@ Bridge::BridgePort::trySend()
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
DPRINTF(BusBridge, " unsuccessful\n");
|
DPRINTF(BusBridge, " unsuccessful\n");
|
||||||
|
pkt->senderState = old_sender_state;
|
||||||
inRetry = true;
|
inRetry = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
DPRINTF(BusBridge, "trySend: queue size: %d outreq: %d outstanding resp: %d\n",
|
DPRINTF(BusBridge, "trySend: queue size: %d outreq: %d outstanding resp: %d\n",
|
||||||
sendQueue.size(), queuedRequests, outstandingResponses);
|
sendQueue.size(), queuedRequests, outstandingResponses);
|
||||||
}
|
}
|
||||||
|
|
|
@ -78,17 +78,19 @@ class Bridge : public MemObject
|
||||||
public:
|
public:
|
||||||
Tick ready;
|
Tick ready;
|
||||||
PacketPtr pkt;
|
PacketPtr pkt;
|
||||||
|
bool nackedHere;
|
||||||
Packet::SenderState *origSenderState;
|
Packet::SenderState *origSenderState;
|
||||||
short origSrc;
|
short origSrc;
|
||||||
bool expectResponse;
|
bool expectResponse;
|
||||||
|
|
||||||
PacketBuffer(PacketPtr _pkt, Tick t, bool nack = false)
|
PacketBuffer(PacketPtr _pkt, Tick t, bool nack = false)
|
||||||
: ready(t), pkt(_pkt),
|
: ready(t), pkt(_pkt), nackedHere(nack),
|
||||||
origSenderState(_pkt->senderState), origSrc(_pkt->getSrc()),
|
origSenderState(_pkt->senderState),
|
||||||
|
origSrc(nack ? _pkt->getDest() : _pkt->getSrc() ),
|
||||||
expectResponse(_pkt->needsResponse() && !nack)
|
expectResponse(_pkt->needsResponse() && !nack)
|
||||||
|
|
||||||
{
|
{
|
||||||
if (!pkt->isResponse() && !nack && !pkt->wasNacked())
|
if (!pkt->isResponse() && !nack)
|
||||||
pkt->senderState = this;
|
pkt->senderState = this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -237,6 +237,7 @@ Bus::recvTiming(PacketPtr pkt)
|
||||||
if (dest_port_id == src) {
|
if (dest_port_id == src) {
|
||||||
// Must be forwarded snoop up from below...
|
// Must be forwarded snoop up from below...
|
||||||
assert(dest == Packet::Broadcast);
|
assert(dest == Packet::Broadcast);
|
||||||
|
assert(src != defaultId); // catch infinite loops
|
||||||
} else {
|
} else {
|
||||||
// send to actual target
|
// send to actual target
|
||||||
if (!dest_port->sendTiming(pkt)) {
|
if (!dest_port->sendTiming(pkt)) {
|
||||||
|
|
25
src/mem/cache/cache_impl.hh
vendored
25
src/mem/cache/cache_impl.hh
vendored
|
@ -606,7 +606,13 @@ Cache<TagStore>::atomicAccess(PacketPtr pkt)
|
||||||
DPRINTF(Cache, "Receive response: %s for addr %x in state %i\n",
|
DPRINTF(Cache, "Receive response: %s for addr %x in state %i\n",
|
||||||
busPkt->cmdString(), busPkt->getAddr(), old_state);
|
busPkt->cmdString(), busPkt->getAddr(), old_state);
|
||||||
|
|
||||||
if (isCacheFill) {
|
bool is_error = busPkt->isError();
|
||||||
|
assert(!busPkt->wasNacked());
|
||||||
|
|
||||||
|
if (is_error && pkt->needsResponse()) {
|
||||||
|
pkt->makeAtomicResponse();
|
||||||
|
pkt->copyError(busPkt);
|
||||||
|
} else if (isCacheFill && !is_error) {
|
||||||
PacketList writebacks;
|
PacketList writebacks;
|
||||||
blk = handleFill(busPkt, blk, writebacks);
|
blk = handleFill(busPkt, blk, writebacks);
|
||||||
satisfyCpuSideRequest(pkt, blk);
|
satisfyCpuSideRequest(pkt, blk);
|
||||||
|
@ -667,6 +673,8 @@ Cache<TagStore>::handleResponse(PacketPtr pkt)
|
||||||
{
|
{
|
||||||
Tick time = curTick + hitLatency;
|
Tick time = curTick + hitLatency;
|
||||||
MSHR *mshr = dynamic_cast<MSHR*>(pkt->senderState);
|
MSHR *mshr = dynamic_cast<MSHR*>(pkt->senderState);
|
||||||
|
bool is_error = pkt->isError();
|
||||||
|
|
||||||
assert(mshr);
|
assert(mshr);
|
||||||
|
|
||||||
if (pkt->wasNacked()) {
|
if (pkt->wasNacked()) {
|
||||||
|
@ -675,7 +683,11 @@ Cache<TagStore>::handleResponse(PacketPtr pkt)
|
||||||
"not implemented\n");
|
"not implemented\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
assert(!pkt->isError());
|
if (is_error) {
|
||||||
|
DPRINTF(Cache, "Cache received packet with error for address %x, "
|
||||||
|
"cmd: %s\n", pkt->getAddr(), pkt->cmdString());
|
||||||
|
}
|
||||||
|
|
||||||
DPRINTF(Cache, "Handling response to %x\n", pkt->getAddr());
|
DPRINTF(Cache, "Handling response to %x\n", pkt->getAddr());
|
||||||
|
|
||||||
MSHRQueue *mq = mshr->queue;
|
MSHRQueue *mq = mshr->queue;
|
||||||
|
@ -702,7 +714,7 @@ Cache<TagStore>::handleResponse(PacketPtr pkt)
|
||||||
miss_latency;
|
miss_latency;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mshr->isCacheFill) {
|
if (mshr->isCacheFill && !is_error) {
|
||||||
DPRINTF(Cache, "Block for addr %x being updated in Cache\n",
|
DPRINTF(Cache, "Block for addr %x being updated in Cache\n",
|
||||||
pkt->getAddr());
|
pkt->getAddr());
|
||||||
|
|
||||||
|
@ -744,13 +756,18 @@ Cache<TagStore>::handleResponse(PacketPtr pkt)
|
||||||
} else {
|
} else {
|
||||||
// not a cache fill, just forwarding response
|
// not a cache fill, just forwarding response
|
||||||
completion_time = tags->getHitLatency() + pkt->finishTime;
|
completion_time = tags->getHitLatency() + pkt->finishTime;
|
||||||
if (pkt->isRead()) {
|
if (pkt->isRead() && !is_error) {
|
||||||
target->pkt->setData(pkt->getPtr<uint8_t>());
|
target->pkt->setData(pkt->getPtr<uint8_t>());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
target->pkt->makeTimingResponse();
|
target->pkt->makeTimingResponse();
|
||||||
|
// if this packet is an error copy that to the new packet
|
||||||
|
if (is_error)
|
||||||
|
target->pkt->copyError(pkt);
|
||||||
cpuSidePort->respond(target->pkt, completion_time);
|
cpuSidePort->respond(target->pkt, completion_time);
|
||||||
} else {
|
} else {
|
||||||
|
// I don't believe that a snoop can be in an error state
|
||||||
|
assert(!is_error);
|
||||||
// response to snoop request
|
// response to snoop request
|
||||||
DPRINTF(Cache, "processing deferred snoop...\n");
|
DPRINTF(Cache, "processing deferred snoop...\n");
|
||||||
handleSnoop(target->pkt, blk, true, true);
|
handleSnoop(target->pkt, blk, true, true);
|
||||||
|
|
|
@ -117,11 +117,11 @@ MemCmd::commandInfo[] =
|
||||||
{ SET5(IsRead, IsWrite, NeedsExclusive, IsResponse, HasData),
|
{ SET5(IsRead, IsWrite, NeedsExclusive, IsResponse, HasData),
|
||||||
InvalidCmd, "SwapResp" },
|
InvalidCmd, "SwapResp" },
|
||||||
/* NetworkNackError -- nacked at network layer (not by protocol) */
|
/* NetworkNackError -- nacked at network layer (not by protocol) */
|
||||||
{ SET2(IsRequest, IsError), InvalidCmd, "NetworkNackError" },
|
{ SET2(IsResponse, IsError), InvalidCmd, "NetworkNackError" },
|
||||||
/* InvalidDestError -- packet dest field invalid */
|
/* InvalidDestError -- packet dest field invalid */
|
||||||
{ SET2(IsRequest, IsError), InvalidCmd, "InvalidDestError" },
|
{ SET2(IsResponse, IsError), InvalidCmd, "InvalidDestError" },
|
||||||
/* BadAddressError -- memory address invalid */
|
/* BadAddressError -- memory address invalid */
|
||||||
{ SET2(IsRequest, IsError), InvalidCmd, "BadAddressError" }
|
{ SET2(IsResponse, IsError), InvalidCmd, "BadAddressError" }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -332,10 +332,11 @@ class Packet : public FastAlloc
|
||||||
// Network error conditions... encapsulate them as methods since
|
// Network error conditions... encapsulate them as methods since
|
||||||
// their encoding keeps changing (from result field to command
|
// their encoding keeps changing (from result field to command
|
||||||
// field, etc.)
|
// field, etc.)
|
||||||
void setNacked() { origCmd = cmd; cmd = MemCmd::NetworkNackError; }
|
void setNacked() { assert(isResponse()); cmd = MemCmd::NetworkNackError; }
|
||||||
void setBadAddress() { origCmd = cmd; cmd = MemCmd::BadAddressError; }
|
void setBadAddress() { assert(isResponse()); cmd = MemCmd::BadAddressError; }
|
||||||
bool wasNacked() { return cmd == MemCmd::NetworkNackError; }
|
bool wasNacked() { return cmd == MemCmd::NetworkNackError; }
|
||||||
bool hadBadAddress() { return cmd == MemCmd::BadAddressError; }
|
bool hadBadAddress() { return cmd == MemCmd::BadAddressError; }
|
||||||
|
void copyError(Packet *pkt) { assert(pkt->isError()); cmd = pkt->cmd; }
|
||||||
|
|
||||||
bool nic_pkt() { panic("Unimplemented"); M5_DUMMY_RETURN }
|
bool nic_pkt() { panic("Unimplemented"); M5_DUMMY_RETURN }
|
||||||
|
|
||||||
|
@ -431,6 +432,7 @@ class Packet : public FastAlloc
|
||||||
{
|
{
|
||||||
assert(needsResponse());
|
assert(needsResponse());
|
||||||
assert(isRequest());
|
assert(isRequest());
|
||||||
|
origCmd = cmd;
|
||||||
cmd = cmd.responseCommand();
|
cmd = cmd.responseCommand();
|
||||||
dest = src;
|
dest = src;
|
||||||
destValid = srcValid;
|
destValid = srcValid;
|
||||||
|
|
Loading…
Reference in a new issue