#include "arch/isa_traits.hh"
#include "base/misc.hh"
+#include "base/random.hh"
#include "config/full_system.hh"
#include "mem/packet_access.hh"
#include "mem/physical.hh"
-#include "sim/builder.hh"
#include "sim/eventq.hh"
#include "sim/host.hh"
using namespace std;
using namespace TheISA;
-PhysicalMemory::PhysicalMemory(Params *p)
- : MemObject(p->name), pmemAddr(NULL), lat(p->latency), _params(p)
+PhysicalMemory::PhysicalMemory(const Params *p)
+ : MemObject(p), pmemAddr(NULL), pagePtr(0),
+ lat(p->latency), lat_var(p->latency_var),
+ cachedSize(params()->range.size()), cachedStart(params()->range.start)
{
- if (params()->addrRange.size() % TheISA::PageBytes != 0)
+ if (params()->range.size() % TheISA::PageBytes != 0)
panic("Memory Size not divisible by page size\n");
+ if (params()->null)
+ return;
+
int map_flags = MAP_ANON | MAP_PRIVATE;
- pmemAddr = (uint8_t *)mmap(NULL, params()->addrRange.size(), PROT_READ | PROT_WRITE,
- map_flags, -1, 0);
+ pmemAddr = (uint8_t *)mmap(NULL, params()->range.size(),
+ PROT_READ | PROT_WRITE, map_flags, -1, 0);
if (pmemAddr == (void *)MAP_FAILED) {
perror("mmap");
}
//If requested, initialize all the memory to 0
- if(params()->zero)
- memset(pmemAddr, 0, params()->addrRange.size());
-
- pagePtr = 0;
+ if (p->zero)
+ memset(pmemAddr, 0, p->range.size());
}
void
PhysicalMemory::~PhysicalMemory()
{
if (pmemAddr)
- munmap((char*)pmemAddr, params()->addrRange.size());
+ munmap((char*)pmemAddr, params()->range.size());
//Remove memPorts?
}
Tick
PhysicalMemory::calculateLatency(PacketPtr pkt)
{
- return lat;
+ Tick latency = lat;
+ if (lat_var != 0)
+ latency += random_mt.random<Tick>(0, lat_var);
+ return latency;
}
// Add load-locked to tracking list. Should only be called if the
// operation is a load and the LOCKED flag is set.
void
-PhysicalMemory::trackLoadLocked(Request *req)
+PhysicalMemory::trackLoadLocked(PacketPtr pkt)
{
+ Request *req = pkt->req;
Addr paddr = LockedAddr::mask(req->getPaddr());
// first we check if we already have a locked addr for this
for (i = lockedAddrList.begin(); i != lockedAddrList.end(); ++i) {
if (i->matchesContext(req)) {
- DPRINTF(LLSC, "Modifying lock record: cpu %d thread %d addr %#x\n",
- req->getCpuNum(), req->getThreadNum(), paddr);
+ DPRINTF(LLSC, "Modifying lock record: context %d addr %#x\n",
+ req->contextId(), paddr);
i->addr = paddr;
return;
}
}
// no record for this xc: need to allocate a new one
- DPRINTF(LLSC, "Adding lock record: cpu %d thread %d addr %#x\n",
- req->getCpuNum(), req->getThreadNum(), paddr);
+ DPRINTF(LLSC, "Adding lock record: context %d addr %#x\n",
+ req->contextId(), paddr);
lockedAddrList.push_front(LockedAddr(req));
}
// conflict with locked addresses, and for success/failure of store
// conditionals.
bool
-PhysicalMemory::checkLockedAddrList(Request *req)
+PhysicalMemory::checkLockedAddrList(PacketPtr pkt)
{
+ Request *req = pkt->req;
Addr paddr = LockedAddr::mask(req->getPaddr());
- bool isLocked = req->isLocked();
+ bool isLocked = pkt->isLocked();
// Initialize return value. Non-conditional stores always
// succeed. Assume conditional stores will fail until proven
// it's a store conditional, and as far as the memory
// system can tell, the requesting context's lock is
// still valid.
- DPRINTF(LLSC, "StCond success: cpu %d thread %d addr %#x\n",
- req->getCpuNum(), req->getThreadNum(), paddr);
+ DPRINTF(LLSC, "StCond success: context %d addr %#x\n",
+ req->contextId(), paddr);
success = true;
}
// Get rid of our record of this lock and advance to next
- DPRINTF(LLSC, "Erasing lock record: cpu %d thread %d addr %#x\n",
- i->cpuNum, i->threadNum, paddr);
+ DPRINTF(LLSC, "Erasing lock record: context %d addr %#x\n",
+ i->contextId, paddr);
i = lockedAddrList.erase(i);
}
else {
return success;
}
-void
-PhysicalMemory::doFunctionalAccess(PacketPtr pkt)
+
+#if TRACING_ON
+
+#define CASE(A, T) \
+ case sizeof(T): \
+ DPRINTF(MemoryAccess, A " of size %i on address 0x%x data 0x%x\n", \
+ pkt->getSize(), pkt->getAddr(), pkt->get<T>()); \
+ break
+
+
+#define TRACE_PACKET(A) \
+ do { \
+ switch (pkt->getSize()) { \
+ CASE(A, uint64_t); \
+ CASE(A, uint32_t); \
+ CASE(A, uint16_t); \
+ CASE(A, uint8_t); \
+ default: \
+ DPRINTF(MemoryAccess, A " of size %i on address 0x%x\n", \
+ pkt->getSize(), pkt->getAddr()); \
+ } \
+ } while (0)
+
+#else
+
+#define TRACE_PACKET(A)
+
+#endif
+
+Tick
+PhysicalMemory::doAtomicAccess(PacketPtr pkt)
{
assert(pkt->getAddr() >= start() &&
pkt->getAddr() + pkt->getSize() <= start() + size());
- if (pkt->isRead()) {
- if (pkt->req->isLocked()) {
- trackLoadLocked(pkt->req);
- }
- memcpy(pkt->getPtr<uint8_t>(), pmemAddr + pkt->getAddr() - start(),
- pkt->getSize());
-#if TRACING_ON
- switch (pkt->getSize()) {
- case sizeof(uint64_t):
- DPRINTF(MemoryAccess, "Read of size %i on address 0x%x data 0x%x\n",
- pkt->getSize(), pkt->getAddr(),pkt->get<uint64_t>());
- break;
- case sizeof(uint32_t):
- DPRINTF(MemoryAccess, "Read of size %i on address 0x%x data 0x%x\n",
- pkt->getSize(), pkt->getAddr(),pkt->get<uint32_t>());
- break;
- case sizeof(uint16_t):
- DPRINTF(MemoryAccess, "Read of size %i on address 0x%x data 0x%x\n",
- pkt->getSize(), pkt->getAddr(),pkt->get<uint16_t>());
- break;
- case sizeof(uint8_t):
- DPRINTF(MemoryAccess, "Read of size %i on address 0x%x data 0x%x\n",
- pkt->getSize(), pkt->getAddr(),pkt->get<uint8_t>());
- break;
- default:
- DPRINTF(MemoryAccess, "Read of size %i on address 0x%x\n",
- pkt->getSize(), pkt->getAddr());
- }
-#endif
+ if (pkt->memInhibitAsserted()) {
+ DPRINTF(MemoryAccess, "mem inhibited on 0x%x: not responding\n",
+ pkt->getAddr());
+ return 0;
}
- else if (pkt->isWrite()) {
- if (writeOK(pkt->req)) {
- memcpy(pmemAddr + pkt->getAddr() - start(), pkt->getPtr<uint8_t>(),
- pkt->getSize());
-#if TRACING_ON
- switch (pkt->getSize()) {
- case sizeof(uint64_t):
- DPRINTF(MemoryAccess, "Write of size %i on address 0x%x data 0x%x\n",
- pkt->getSize(), pkt->getAddr(),pkt->get<uint64_t>());
- break;
- case sizeof(uint32_t):
- DPRINTF(MemoryAccess, "Write of size %i on address 0x%x data 0x%x\n",
- pkt->getSize(), pkt->getAddr(),pkt->get<uint32_t>());
- break;
- case sizeof(uint16_t):
- DPRINTF(MemoryAccess, "Write of size %i on address 0x%x data 0x%x\n",
- pkt->getSize(), pkt->getAddr(),pkt->get<uint16_t>());
- break;
- case sizeof(uint8_t):
- DPRINTF(MemoryAccess, "Write of size %i on address 0x%x data 0x%x\n",
- pkt->getSize(), pkt->getAddr(),pkt->get<uint8_t>());
- break;
- default:
- DPRINTF(MemoryAccess, "Write of size %i on address 0x%x\n",
- pkt->getSize(), pkt->getAddr());
- }
-#endif
- }
- } else if (pkt->isInvalidate()) {
- //upgrade or invalidate
- pkt->flags |= SATISFIED;
- } else if (pkt->isReadWrite()) {
+
+ uint8_t *hostAddr = pmemAddr + pkt->getAddr() - start();
+
+ if (pkt->cmd == MemCmd::SwapReq) {
IntReg overwrite_val;
bool overwrite_mem;
uint64_t condition_val64;
uint32_t condition_val32;
+ if (!pmemAddr)
+ panic("Swap only works if there is real memory (i.e. null=False)");
assert(sizeof(IntReg) >= pkt->getSize());
overwrite_mem = true;
// keep a copy of our possible write value, and copy what is at the
// memory address into the packet
std::memcpy(&overwrite_val, pkt->getPtr<uint8_t>(), pkt->getSize());
- std::memcpy(pkt->getPtr<uint8_t>(), pmemAddr + pkt->getAddr() - start(),
- pkt->getSize());
+ std::memcpy(pkt->getPtr<uint8_t>(), hostAddr, pkt->getSize());
if (pkt->req->isCondSwap()) {
if (pkt->getSize() == sizeof(uint64_t)) {
condition_val64 = pkt->req->getExtraData();
- overwrite_mem = !std::memcmp(&condition_val64, pmemAddr +
- pkt->getAddr() - start(), sizeof(uint64_t));
+ overwrite_mem = !std::memcmp(&condition_val64, hostAddr,
+ sizeof(uint64_t));
} else if (pkt->getSize() == sizeof(uint32_t)) {
condition_val32 = (uint32_t)pkt->req->getExtraData();
- overwrite_mem = !std::memcmp(&condition_val32, pmemAddr +
- pkt->getAddr() - start(), sizeof(uint32_t));
+ overwrite_mem = !std::memcmp(&condition_val32, hostAddr,
+ sizeof(uint32_t));
} else
panic("Invalid size for conditional read/write\n");
}
if (overwrite_mem)
- std::memcpy(pmemAddr + pkt->getAddr() - start(),
- &overwrite_val, pkt->getSize());
+ std::memcpy(hostAddr, &overwrite_val, pkt->getSize());
-#if TRACING_ON
- switch (pkt->getSize()) {
- case sizeof(uint64_t):
- DPRINTF(MemoryAccess, "Read/Write of size %i on address 0x%x old data 0x%x\n",
- pkt->getSize(), pkt->getAddr(),pkt->get<uint64_t>());
- DPRINTF(MemoryAccess, "New Data 0x%x %s conditional (0x%x) and %s \n",
- overwrite_mem, pkt->req->isCondSwap() ? "was" : "wasn't",
- condition_val64, overwrite_mem ? "happened" : "didn't happen");
- break;
- case sizeof(uint32_t):
- DPRINTF(MemoryAccess, "Read/Write of size %i on address 0x%x old data 0x%x\n",
- pkt->getSize(), pkt->getAddr(),pkt->get<uint32_t>());
- DPRINTF(MemoryAccess, "New Data 0x%x %s conditional (0x%x) and %s \n",
- overwrite_mem, pkt->req->isCondSwap() ? "was" : "wasn't",
- condition_val32, overwrite_mem ? "happened" : "didn't happen");
- break;
- case sizeof(uint16_t):
- DPRINTF(MemoryAccess, "Read/Write of size %i on address 0x%x old data 0x%x\n",
- pkt->getSize(), pkt->getAddr(),pkt->get<uint16_t>());
- DPRINTF(MemoryAccess, "New Data 0x%x wasn't conditional and happned\n",
- overwrite_mem);
- break;
- case sizeof(uint8_t):
- DPRINTF(MemoryAccess, "Read/Write of size %i on address 0x%x old data 0x%x\n",
- pkt->getSize(), pkt->getAddr(),pkt->get<uint8_t>());
- DPRINTF(MemoryAccess, "New Data 0x%x wasn't conditional and happned\n",
- overwrite_mem);
- break;
- default:
- DPRINTF(MemoryAccess, "Read/Write of size %i on address 0x%x\n",
- pkt->getSize(), pkt->getAddr());
+ TRACE_PACKET("Read/Write");
+ } else if (pkt->isRead()) {
+ assert(!pkt->isWrite());
+ if (pkt->isLocked()) {
+ trackLoadLocked(pkt);
+ }
+ if (pmemAddr)
+ memcpy(pkt->getPtr<uint8_t>(), hostAddr, pkt->getSize());
+ TRACE_PACKET("Read");
+ } else if (pkt->isWrite()) {
+ if (writeOK(pkt)) {
+ if (pmemAddr)
+ memcpy(hostAddr, pkt->getPtr<uint8_t>(), pkt->getSize());
+ TRACE_PACKET("Write");
+ }
+ } else if (pkt->isInvalidate()) {
+ //upgrade or invalidate
+ if (pkt->needsResponse()) {
+ pkt->makeAtomicResponse();
}
-#endif
} else {
panic("unimplemented");
}
- pkt->result = Packet::Success;
+ if (pkt->needsResponse()) {
+ pkt->makeAtomicResponse();
+ }
+ return calculateLatency(pkt);
}
+
+void
+PhysicalMemory::doFunctionalAccess(PacketPtr pkt)
+{
+ assert(pkt->getAddr() >= start() &&
+ pkt->getAddr() + pkt->getSize() <= start() + size());
+
+
+ uint8_t *hostAddr = pmemAddr + pkt->getAddr() - start();
+
+ if (pkt->isRead()) {
+ if (pmemAddr)
+ memcpy(pkt->getPtr<uint8_t>(), hostAddr, pkt->getSize());
+ TRACE_PACKET("Read");
+ pkt->makeAtomicResponse();
+ } else if (pkt->isWrite()) {
+ if (pmemAddr)
+ memcpy(hostAddr, pkt->getPtr<uint8_t>(), pkt->getSize());
+ TRACE_PACKET("Write");
+ pkt->makeAtomicResponse();
+ } else if (pkt->isPrint()) {
+ Packet::PrintReqState *prs =
+ dynamic_cast<Packet::PrintReqState*>(pkt->senderState);
+ // Need to call printLabels() explicitly since we're not going
+ // through printObj().
+ prs->printLabels();
+ // Right now we just print the single byte at the specified address.
+ ccprintf(prs->os, "%s%#x\n", prs->curPrefix(), *hostAddr);
+ } else {
+ panic("PhysicalMemory: unimplemented functional command %s",
+ pkt->cmdString());
+ }
+}
+
+
Port *
PhysicalMemory::getPort(const std::string &if_name, int idx)
{
PhysicalMemory::MemoryPort::MemoryPort(const std::string &_name,
PhysicalMemory *_memory)
- : SimpleTimingPort(_name), memory(_memory)
+ : SimpleTimingPort(_name, _memory), memory(_memory)
{ }
void
void
PhysicalMemory::MemoryPort::getDeviceAddressRanges(AddrRangeList &resp,
- AddrRangeList &snoop)
+ bool &snoop)
{
memory->getAddressRanges(resp, snoop);
}
void
-PhysicalMemory::getAddressRanges(AddrRangeList &resp, AddrRangeList &snoop)
+PhysicalMemory::getAddressRanges(AddrRangeList &resp, bool &snoop)
{
- snoop.clear();
+ snoop = false;
resp.clear();
- resp.push_back(RangeSize(start(),
- params()->addrRange.size()));
+ resp.push_back(RangeSize(start(), params()->range.size()));
}
int
Tick
PhysicalMemory::MemoryPort::recvAtomic(PacketPtr pkt)
{
- memory->doFunctionalAccess(pkt);
- return memory->calculateLatency(pkt);
+ return memory->doAtomicAccess(pkt);
}
void
PhysicalMemory::MemoryPort::recvFunctional(PacketPtr pkt)
{
- //Since we are overriding the function, make sure to have the impl of the
- //check or functional accesses here.
- std::list<std::pair<Tick,PacketPtr> >::iterator i = transmitList.begin();
- std::list<std::pair<Tick,PacketPtr> >::iterator end = transmitList.end();
- bool notDone = true;
-
- while (i != end && notDone) {
- PacketPtr target = i->second;
- // If the target contains data, and it overlaps the
- // probed request, need to update data
- if (target->intersect(pkt))
- notDone = fixPacket(pkt, target);
- i++;
+ pkt->pushLabel(memory->name());
+
+ if (!checkFunctional(pkt)) {
+ // Default implementation of SimpleTimingPort::recvFunctional()
+ // calls recvAtomic() and throws away the latency; we can save a
+ // little here by just not calculating the latency.
+ memory->doFunctionalAccess(pkt);
}
- // Default implementation of SimpleTimingPort::recvFunctional()
- // calls recvAtomic() and throws away the latency; we can save a
- // little here by just not calculating the latency.
- memory->doFunctionalAccess(pkt);
+ pkt->popLabel();
}
unsigned int
void
PhysicalMemory::serialize(ostream &os)
{
+ if (!pmemAddr)
+ return;
+
gzFile compressedMem;
string filename = name() + ".physmem";
fatal("Insufficient memory to allocate compression state for %s\n",
filename);
- if (gzwrite(compressedMem, pmemAddr, params()->addrRange.size()) != params()->addrRange.size()) {
+ if (gzwrite(compressedMem, pmemAddr, params()->range.size()) !=
+ params()->range.size()) {
fatal("Write failed on physical memory checkpoint file '%s'\n",
filename);
}
void
PhysicalMemory::unserialize(Checkpoint *cp, const string §ion)
{
+ if (!pmemAddr)
+ return;
+
gzFile compressedMem;
long *tempPage;
long *pmem_current;
uint32_t bytesRead;
const int chunkSize = 16384;
-
string filename;
UNSERIALIZE_SCALAR(filename);
// unmap file that was mmaped in the constructor
// This is done here to make sure that gzip and open don't muck with our
// nice large space of memory before we reallocate it
- munmap((char*)pmemAddr, params()->addrRange.size());
+ munmap((char*)pmemAddr, params()->range.size());
- pmemAddr = (uint8_t *)mmap(NULL, params()->addrRange.size(), PROT_READ | PROT_WRITE,
- MAP_ANON | MAP_PRIVATE, -1, 0);
+ pmemAddr = (uint8_t *)mmap(NULL, params()->range.size(),
+ PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0);
if (pmemAddr == (void *)MAP_FAILED) {
perror("mmap");
fatal("Unable to malloc memory to read file %s\n", filename);
/* Only copy bytes that are non-zero, so we don't give the VM system hell */
- while (curSize < params()->addrRange.size()) {
+ while (curSize < params()->range.size()) {
bytesRead = gzread(compressedMem, tempPage, chunkSize);
- if (bytesRead != chunkSize && bytesRead != params()->addrRange.size() - curSize)
+ if (bytesRead != chunkSize &&
+ bytesRead != params()->range.size() - curSize)
fatal("Read failed on physical memory checkpoint file '%s'"
" got %d bytes, expected %d or %d bytes\n",
- filename, bytesRead, chunkSize, params()->addrRange.size()-curSize);
+ filename, bytesRead, chunkSize,
+ params()->range.size() - curSize);
assert(bytesRead % sizeof(long) == 0);
}
-
-BEGIN_DECLARE_SIM_OBJECT_PARAMS(PhysicalMemory)
-
- Param<string> file;
- Param<Range<Addr> > range;
- Param<Tick> latency;
- Param<bool> zero;
-
-END_DECLARE_SIM_OBJECT_PARAMS(PhysicalMemory)
-
-BEGIN_INIT_SIM_OBJECT_PARAMS(PhysicalMemory)
-
- INIT_PARAM_DFLT(file, "memory mapped file", ""),
- INIT_PARAM(range, "Device Address Range"),
- INIT_PARAM(latency, "Memory access latency"),
- INIT_PARAM(zero, "Zero initialize memory")
-
-END_INIT_SIM_OBJECT_PARAMS(PhysicalMemory)
-
-CREATE_SIM_OBJECT(PhysicalMemory)
+PhysicalMemory *
+PhysicalMemoryParams::create()
{
- PhysicalMemory::Params *p = new PhysicalMemory::Params;
- p->name = getInstanceName();
- p->addrRange = range;
- p->latency = latency;
- p->zero = zero;
- return new PhysicalMemory(p);
+ return new PhysicalMemory(this);
}
-
-REGISTER_SIM_OBJECT("PhysicalMemory", PhysicalMemory)