2006-04-28 21:37:48 +02:00
|
|
|
/*
|
|
|
|
* Copyright (c) 2006 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.
|
2006-06-01 01:26:56 +02:00
|
|
|
*
|
|
|
|
* Authors: Ali Saidi
|
|
|
|
* Steve Reinhardt
|
2006-04-28 21:37:48 +02:00
|
|
|
*/
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @file
|
|
|
|
* Definition of the Packet Class, a packet is a transaction occuring
|
|
|
|
* between a single level of the memory heirarchy (ie L1->L2).
|
|
|
|
*/
|
2006-10-12 20:15:09 +02:00
|
|
|
|
|
|
|
#include <iostream>
|
2007-01-27 00:48:51 +01:00
|
|
|
#include <cstring>
|
2006-04-29 23:37:25 +02:00
|
|
|
#include "base/misc.hh"
|
2006-10-12 20:15:09 +02:00
|
|
|
#include "base/trace.hh"
|
2006-10-20 08:38:45 +02:00
|
|
|
#include "mem/packet.hh"
|
2006-04-28 21:37:48 +02:00
|
|
|
|
2007-02-07 19:53:37 +01:00
|
|
|
// The one downside to bitsets is that static initializers can get ugly.
|
|
|
|
#define SET1(a1) (1 << (a1))
|
|
|
|
#define SET2(a1, a2) (SET1(a1) | SET1(a2))
|
|
|
|
#define SET3(a1, a2, a3) (SET2(a1, a2) | SET1(a3))
|
|
|
|
#define SET4(a1, a2, a3, a4) (SET3(a1, a2, a3) | SET1(a4))
|
|
|
|
#define SET5(a1, a2, a3, a4, a5) (SET4(a1, a2, a3, a4) | SET1(a5))
|
|
|
|
#define SET6(a1, a2, a3, a4, a5, a6) (SET5(a1, a2, a3, a4, a5) | SET1(a6))
|
2006-05-26 20:17:33 +02:00
|
|
|
|
2007-02-07 19:53:37 +01:00
|
|
|
const MemCmd::CommandInfo
|
|
|
|
MemCmd::commandInfo[] =
|
2006-05-26 20:17:33 +02:00
|
|
|
{
|
2007-02-07 19:53:37 +01:00
|
|
|
/* InvalidCmd */
|
|
|
|
{ 0, InvalidCmd, "InvalidCmd" },
|
|
|
|
/* ReadReq */
|
|
|
|
{ SET3(IsRead, IsRequest, NeedsResponse), ReadResp, "ReadReq" },
|
2007-05-22 15:29:48 +02:00
|
|
|
/* ReadResp */
|
|
|
|
{ SET3(IsRead, IsResponse, HasData), InvalidCmd, "ReadResp" },
|
2007-02-07 19:53:37 +01:00
|
|
|
/* WriteReq */
|
2007-06-18 02:27:53 +02:00
|
|
|
{ SET5(IsWrite, NeedsExclusive, IsRequest, NeedsResponse, HasData),
|
2007-02-07 19:53:37 +01:00
|
|
|
WriteResp, "WriteReq" },
|
|
|
|
/* WriteResp */
|
2007-06-18 02:27:53 +02:00
|
|
|
{ SET3(IsWrite, NeedsExclusive, IsResponse), InvalidCmd, "WriteResp" },
|
2007-02-07 19:53:37 +01:00
|
|
|
/* Writeback */
|
2007-06-21 20:59:17 +02:00
|
|
|
{ SET4(IsWrite, NeedsExclusive, IsRequest, HasData),
|
|
|
|
InvalidCmd, "Writeback" },
|
2007-02-07 19:53:37 +01:00
|
|
|
/* SoftPFReq */
|
|
|
|
{ SET4(IsRead, IsRequest, IsSWPrefetch, NeedsResponse),
|
|
|
|
SoftPFResp, "SoftPFReq" },
|
|
|
|
/* HardPFReq */
|
|
|
|
{ SET4(IsRead, IsRequest, IsHWPrefetch, NeedsResponse),
|
|
|
|
HardPFResp, "HardPFReq" },
|
|
|
|
/* SoftPFResp */
|
|
|
|
{ SET4(IsRead, IsResponse, IsSWPrefetch, HasData),
|
|
|
|
InvalidCmd, "SoftPFResp" },
|
|
|
|
/* HardPFResp */
|
|
|
|
{ SET4(IsRead, IsResponse, IsHWPrefetch, HasData),
|
|
|
|
InvalidCmd, "HardPFResp" },
|
|
|
|
/* WriteInvalidateReq */
|
2007-06-18 02:27:53 +02:00
|
|
|
{ SET6(IsWrite, NeedsExclusive, IsInvalidate,
|
|
|
|
IsRequest, HasData, NeedsResponse),
|
2007-02-07 19:53:37 +01:00
|
|
|
WriteInvalidateResp, "WriteInvalidateReq" },
|
|
|
|
/* WriteInvalidateResp */
|
2007-06-18 02:27:53 +02:00
|
|
|
{ SET4(IsWrite, NeedsExclusive, IsInvalidate, IsResponse),
|
2007-02-07 19:53:37 +01:00
|
|
|
InvalidCmd, "WriteInvalidateResp" },
|
|
|
|
/* UpgradeReq */
|
2007-06-21 20:59:17 +02:00
|
|
|
{ SET4(IsInvalidate, NeedsExclusive, IsRequest, NeedsResponse),
|
|
|
|
UpgradeResp, "UpgradeReq" },
|
|
|
|
/* UpgradeResp */
|
|
|
|
{ SET3(IsInvalidate, NeedsExclusive, IsResponse),
|
|
|
|
InvalidCmd, "UpgradeResp" },
|
2007-02-07 19:53:37 +01:00
|
|
|
/* ReadExReq */
|
2007-06-18 02:27:53 +02:00
|
|
|
{ SET5(IsRead, NeedsExclusive, IsInvalidate, IsRequest, NeedsResponse),
|
2007-02-07 19:53:37 +01:00
|
|
|
ReadExResp, "ReadExReq" },
|
|
|
|
/* ReadExResp */
|
2007-06-18 02:27:53 +02:00
|
|
|
{ SET5(IsRead, NeedsExclusive, IsInvalidate, IsResponse, HasData),
|
2007-02-12 19:06:30 +01:00
|
|
|
InvalidCmd, "ReadExResp" },
|
2007-06-18 02:27:53 +02:00
|
|
|
/* LoadLockedReq */
|
|
|
|
{ SET4(IsRead, IsLocked, IsRequest, NeedsResponse),
|
|
|
|
ReadResp, "LoadLockedReq" },
|
|
|
|
/* LoadLockedResp */
|
|
|
|
{ SET4(IsRead, IsLocked, IsResponse, HasData),
|
|
|
|
InvalidCmd, "LoadLockedResp" },
|
|
|
|
/* StoreCondReq */
|
|
|
|
{ SET6(IsWrite, NeedsExclusive, IsLocked,
|
|
|
|
IsRequest, NeedsResponse, HasData),
|
|
|
|
StoreCondResp, "StoreCondReq" },
|
|
|
|
/* StoreCondResp */
|
|
|
|
{ SET4(IsWrite, NeedsExclusive, IsLocked, IsResponse),
|
|
|
|
InvalidCmd, "StoreCondResp" },
|
2007-02-12 19:06:30 +01:00
|
|
|
/* SwapReq -- for Swap ldstub type operations */
|
2007-06-18 02:27:53 +02:00
|
|
|
{ SET6(IsRead, IsWrite, NeedsExclusive, IsRequest, HasData, NeedsResponse),
|
2007-02-12 19:06:30 +01:00
|
|
|
SwapResp, "SwapReq" },
|
|
|
|
/* SwapResp -- for Swap ldstub type operations */
|
2007-06-18 02:27:53 +02:00
|
|
|
{ SET5(IsRead, IsWrite, NeedsExclusive, IsResponse, HasData),
|
2007-02-12 19:06:30 +01:00
|
|
|
InvalidCmd, "SwapResp" }
|
2007-02-07 19:53:37 +01:00
|
|
|
};
|
2006-06-28 20:35:00 +02:00
|
|
|
|
2006-05-02 00:53:28 +02:00
|
|
|
|
|
|
|
/** delete the data pointed to in the data pointer. Ok to call to matter how
|
|
|
|
* data was allocted. */
|
|
|
|
void
|
2006-05-26 20:17:33 +02:00
|
|
|
Packet::deleteData()
|
|
|
|
{
|
2006-05-02 00:53:28 +02:00
|
|
|
assert(staticData || dynamicData);
|
|
|
|
if (staticData)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (arrayData)
|
|
|
|
delete [] data;
|
|
|
|
else
|
|
|
|
delete data;
|
|
|
|
}
|
|
|
|
|
|
|
|
/** If there isn't data in the packet, allocate some. */
|
|
|
|
void
|
2006-05-26 20:17:33 +02:00
|
|
|
Packet::allocate()
|
|
|
|
{
|
2006-05-02 00:53:28 +02:00
|
|
|
if (data)
|
|
|
|
return;
|
|
|
|
assert(!staticData);
|
|
|
|
dynamicData = true;
|
|
|
|
arrayData = true;
|
2006-05-26 20:17:33 +02:00
|
|
|
data = new uint8_t[getSize()];
|
2006-05-02 00:53:28 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/** Do the packet modify the same addresses. */
|
|
|
|
bool
|
2006-10-20 09:10:12 +02:00
|
|
|
Packet::intersect(PacketPtr p)
|
2006-05-26 20:17:33 +02:00
|
|
|
{
|
|
|
|
Addr s1 = getAddr();
|
2006-10-10 23:49:31 +02:00
|
|
|
Addr e1 = getAddr() + getSize() - 1;
|
2006-05-26 20:17:33 +02:00
|
|
|
Addr s2 = p->getAddr();
|
2006-10-10 23:49:31 +02:00
|
|
|
Addr e2 = p->getAddr() + p->getSize() - 1;
|
2006-05-02 00:53:28 +02:00
|
|
|
|
2006-10-10 23:49:31 +02:00
|
|
|
return !(s1 > e2 || e1 < s2);
|
2006-11-12 12:35:39 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
|
|
|
fixDelayedResponsePacket(PacketPtr func, PacketPtr timing)
|
|
|
|
{
|
|
|
|
bool result;
|
|
|
|
|
|
|
|
if (timing->isRead() || timing->isWrite()) {
|
2007-02-07 19:53:37 +01:00
|
|
|
// Ugly hack to deal with the fact that we queue the requests
|
|
|
|
// and don't convert them to responses until we issue them on
|
|
|
|
// the bus. I tried to avoid this by converting packets to
|
|
|
|
// responses right away, but this breaks during snoops where a
|
|
|
|
// responder may do the conversion before other caches have
|
|
|
|
// done the snoop. Would work if we copied the packet instead
|
|
|
|
// of just hanging on to a pointer.
|
|
|
|
MemCmd oldCmd = timing->cmd;
|
|
|
|
timing->cmd = timing->cmd.responseCommand();
|
2006-11-12 12:35:39 +01:00
|
|
|
result = fixPacket(func, timing);
|
2007-02-07 19:53:37 +01:00
|
|
|
timing->cmd = oldCmd;
|
2006-11-12 12:35:39 +01:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
//Don't toggle if it isn't a read/write response
|
|
|
|
result = fixPacket(func, timing);
|
|
|
|
}
|
|
|
|
|
|
|
|
return result;
|
2006-05-02 00:53:28 +02:00
|
|
|
}
|
|
|
|
|
2006-05-26 20:17:33 +02:00
|
|
|
bool
|
2007-06-18 02:27:53 +02:00
|
|
|
Packet::checkFunctional(Addr addr, int size, uint8_t *data)
|
2006-05-26 20:17:33 +02:00
|
|
|
{
|
2007-06-18 02:27:53 +02:00
|
|
|
Addr func_start = getAddr();
|
|
|
|
Addr func_end = getAddr() + getSize() - 1;
|
|
|
|
Addr val_start = addr;
|
|
|
|
Addr val_end = val_start + size - 1;
|
2006-10-12 20:15:09 +02:00
|
|
|
|
2007-06-18 02:27:53 +02:00
|
|
|
if (func_start > val_end || val_start > func_end) {
|
|
|
|
// no intersection
|
|
|
|
return false;
|
|
|
|
}
|
2006-10-12 20:15:09 +02:00
|
|
|
|
2007-06-18 02:27:53 +02:00
|
|
|
// offset of functional request into supplied value (could be
|
|
|
|
// negative if partial overlap)
|
|
|
|
int offset = func_start - val_start;
|
2006-10-12 20:15:09 +02:00
|
|
|
|
2007-06-18 02:27:53 +02:00
|
|
|
if (isRead()) {
|
|
|
|
if (func_start >= val_start && func_end <= val_end) {
|
|
|
|
allocate();
|
|
|
|
std::memcpy(getPtr<uint8_t>(), data + offset, getSize());
|
|
|
|
result = Packet::Success;
|
|
|
|
return true;
|
2006-10-12 20:15:09 +02:00
|
|
|
} else {
|
2007-05-28 17:04:33 +02:00
|
|
|
// In this case the timing packet only partially satisfies
|
|
|
|
// the request, so we would need more information to make
|
|
|
|
// this work. Like bytes valid in the packet or
|
|
|
|
// something, so the request could continue and get this
|
|
|
|
// bit of possibly newer data along with the older data
|
|
|
|
// not written to yet.
|
2007-06-18 02:27:53 +02:00
|
|
|
panic("Memory value only partially satisfies the functional "
|
|
|
|
"request. Now what?");
|
2006-10-12 20:15:09 +02:00
|
|
|
}
|
2007-06-18 02:27:53 +02:00
|
|
|
} else if (isWrite()) {
|
|
|
|
if (offset >= 0) {
|
|
|
|
std::memcpy(data + offset, getPtr<uint8_t>(),
|
|
|
|
(std::min(func_end, val_end) - func_start) + 1);
|
|
|
|
} else { // val_start > func_start
|
|
|
|
std::memcpy(data, getPtr<uint8_t>() - offset,
|
|
|
|
(std::min(func_end, val_end) - val_start) + 1);
|
2006-10-12 20:15:09 +02:00
|
|
|
}
|
|
|
|
// we always want to keep going with a write
|
2007-06-18 02:27:53 +02:00
|
|
|
return false;
|
2006-10-12 20:15:09 +02:00
|
|
|
} else
|
2007-06-18 02:27:53 +02:00
|
|
|
panic("Don't know how to handle command %s\n", cmdString());
|
2006-10-12 20:15:09 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
std::ostream &
|
|
|
|
operator<<(std::ostream &o, const Packet &p)
|
|
|
|
{
|
|
|
|
|
|
|
|
o << "[0x";
|
|
|
|
o.setf(std::ios_base::hex, std::ios_base::showbase);
|
|
|
|
o << p.getAddr();
|
|
|
|
o.unsetf(std::ios_base::hex| std::ios_base::showbase);
|
|
|
|
o << ":";
|
|
|
|
o.setf(std::ios_base::hex, std::ios_base::showbase);
|
|
|
|
o << p.getAddr() + p.getSize() - 1 << "] ";
|
|
|
|
o.unsetf(std::ios_base::hex| std::ios_base::showbase);
|
|
|
|
|
|
|
|
if (p.result == Packet::Success)
|
|
|
|
o << "Successful ";
|
|
|
|
if (p.result == Packet::BadAddress)
|
|
|
|
o << "BadAddress ";
|
|
|
|
if (p.result == Packet::Nacked)
|
|
|
|
o << "Nacked ";
|
|
|
|
if (p.result == Packet::Unknown)
|
|
|
|
o << "Inflight ";
|
|
|
|
|
|
|
|
if (p.isRead())
|
|
|
|
o << "Read ";
|
|
|
|
if (p.isWrite())
|
2007-02-12 19:06:30 +01:00
|
|
|
o << "Write ";
|
2006-10-12 20:15:09 +02:00
|
|
|
if (p.isInvalidate())
|
2007-02-12 19:06:30 +01:00
|
|
|
o << "Invalidate ";
|
2006-10-12 20:15:09 +02:00
|
|
|
if (p.isRequest())
|
|
|
|
o << "Request ";
|
|
|
|
if (p.isResponse())
|
|
|
|
o << "Response ";
|
|
|
|
if (p.hasData())
|
|
|
|
o << "w/Data ";
|
|
|
|
|
|
|
|
o << std::endl;
|
|
|
|
return o;
|
2006-05-26 20:17:33 +02:00
|
|
|
}
|
2006-10-12 20:15:09 +02:00
|
|
|
|