* Andreas Hansson
*/
-#include "arch/registers.hh"
-#include "config/the_isa.hh"
+#include <vector>
+
+#include "cpu/base.hh"
+#include "cpu/thread_context.hh"
#include "debug/LLSC.hh"
#include "debug/MemoryAccess.hh"
#include "mem/abstract_mem.hh"
confTableReported(p->conf_table_reported), inAddrMap(p->in_addr_map),
_system(NULL)
{
- if (size() % TheISA::PageBytes != 0)
+}
+
+void
+AbstractMemory::init()
+{
+ assert(system());
+
+ if (size() % _system->getPageBytes() != 0)
panic("Memory Size not divisible by page size\n");
}
if (i->addr == paddr) {
DPRINTF(LLSC, "Erasing lock record: context %d addr %#x\n",
i->contextId, paddr);
+ // For ARM, a spinlock would typically include a Wait
+ // For Event (WFE) to conserve energy. The ARMv8
+ // architecture specifies that an event is
+ // automatically generated when clearing the exclusive
+ // monitor to wake up the processor in WFE.
+ ThreadContext* ctx = system()->getThreadContext(i->contextId);
+ ctx->getCpuPtr()->wakeup(ctx->threadId());
i = lockedAddrList.erase(i);
} else {
i++;
A, system()->getMasterName(pkt->req->masterId()), \
pkt->getSize(), pkt->getAddr(), \
pkt->req->isUncacheable() ? 'U' : 'C'); \
- DDUMP(MemoryAccess, pkt->getPtr<uint8_t>(), pkt->getSize()); \
+ DDUMP(MemoryAccess, pkt->getConstPtr<uint8_t>(), pkt->getSize()); \
} \
} while (0)
void
AbstractMemory::access(PacketPtr pkt)
{
- assert(AddrRange(pkt->getAddr(),
- pkt->getAddr() + pkt->getSize() - 1).isSubset(range));
-
- if (pkt->memInhibitAsserted()) {
- DPRINTF(MemoryAccess, "mem inhibited on 0x%x: not responding\n",
+ if (pkt->cacheResponding()) {
+ DPRINTF(MemoryAccess, "Cache responding to %#llx: not responding\n",
pkt->getAddr());
return;
}
+ if (pkt->cmd == MemCmd::CleanEvict || pkt->cmd == MemCmd::WritebackClean) {
+ DPRINTF(MemoryAccess, "CleanEvict on 0x%x: not responding\n",
+ pkt->getAddr());
+ return;
+ }
+
+ assert(AddrRange(pkt->getAddr(),
+ pkt->getAddr() + (pkt->getSize() - 1)).isSubset(range));
+
uint8_t *hostAddr = pmemAddr + pkt->getAddr() - range.start();
if (pkt->cmd == MemCmd::SwapReq) {
- TheISA::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(TheISA::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>(), hostAddr, pkt->getSize());
-
- if (pkt->req->isCondSwap()) {
- if (pkt->getSize() == sizeof(uint64_t)) {
- condition_val64 = pkt->req->getExtraData();
- 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, hostAddr,
- sizeof(uint32_t));
- } else
- panic("Invalid size for conditional read/write\n");
- }
+ if (pkt->isAtomicOp()) {
+ if (pmemAddr) {
+ memcpy(pkt->getPtr<uint8_t>(), hostAddr, pkt->getSize());
+ (*(pkt->getAtomicOp()))(hostAddr);
+ }
+ } else {
+ std::vector<uint8_t> overwrite_val(pkt->getSize());
+ uint64_t condition_val64;
+ uint32_t condition_val32;
+
+ if (!pmemAddr)
+ panic("Swap only works if there is real memory (i.e. null=False)");
+
+ bool 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[0], pkt->getConstPtr<uint8_t>(),
+ 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, hostAddr,
+ sizeof(uint64_t));
+ } else if (pkt->getSize() == sizeof(uint32_t)) {
+ condition_val32 = (uint32_t)pkt->req->getExtraData();
+ overwrite_mem = !std::memcmp(&condition_val32, hostAddr,
+ sizeof(uint32_t));
+ } else
+ panic("Invalid size for conditional read/write\n");
+ }
- if (overwrite_mem)
- std::memcpy(hostAddr, &overwrite_val, pkt->getSize());
+ if (overwrite_mem)
+ std::memcpy(hostAddr, &overwrite_val[0], pkt->getSize());
- assert(!pkt->req->isInstFetch());
- TRACE_PACKET("Read/Write");
- numOther[pkt->req->masterId()]++;
+ assert(!pkt->req->isInstFetch());
+ TRACE_PACKET("Read/Write");
+ numOther[pkt->req->masterId()]++;
+ }
} else if (pkt->isRead()) {
assert(!pkt->isWrite());
if (pkt->isLLSC()) {
bytesRead[pkt->req->masterId()] += pkt->getSize();
if (pkt->req->isInstFetch())
bytesInstRead[pkt->req->masterId()] += pkt->getSize();
+ } else if (pkt->isInvalidate()) {
+ // no need to do anything
+ // this clause is intentionally before the write clause: the only
+ // transaction that is both a write and an invalidate is
+ // WriteInvalidate, and for the sake of consistency, it does not
+ // write to memory. in a cacheless system, there are no WriteInv's
+ // because the Write -> WriteInvalidate rewrite happens in the cache.
} else if (pkt->isWrite()) {
if (writeOK(pkt)) {
if (pmemAddr) {
- memcpy(hostAddr, pkt->getPtr<uint8_t>(), pkt->getSize());
+ memcpy(hostAddr, pkt->getConstPtr<uint8_t>(), pkt->getSize());
DPRINTF(MemoryAccess, "%s wrote %x bytes to address %x\n",
__func__, pkt->getSize(), pkt->getAddr());
}
numWrites[pkt->req->masterId()]++;
bytesWritten[pkt->req->masterId()] += pkt->getSize();
}
- } else if (pkt->isInvalidate()) {
- // no need to do anything
} else {
panic("unimplemented");
}
pkt->makeResponse();
} else if (pkt->isWrite()) {
if (pmemAddr)
- memcpy(hostAddr, pkt->getPtr<uint8_t>(), pkt->getSize());
+ memcpy(hostAddr, pkt->getConstPtr<uint8_t>(), pkt->getSize());
TRACE_PACKET("Write");
pkt->makeResponse();
} else if (pkt->isPrint()) {