* 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.
+ *
+ * Authors: Ron Dreslinski
+ * Ali Saidi
*/
#include <sys/types.h>
#include <iostream>
#include <string>
-
+#include "arch/isa_traits.hh"
#include "base/misc.hh"
#include "config/full_system.hh"
-#include "mem/packet_impl.hh"
#include "mem/physical.hh"
-#include "sim/host.hh"
#include "sim/builder.hh"
#include "sim/eventq.hh"
-#include "arch/isa_traits.hh"
-
+#include "sim/host.hh"
using namespace std;
using namespace TheISA;
-PhysicalMemory::MemResponseEvent::MemResponseEvent(Packet *pkt, MemoryPort* _m)
- : Event(&mainEventQueue, CPU_Tick_Pri), pkt(pkt), memoryPort(_m)
+PhysicalMemory::PhysicalMemory(Params *p)
+ : MemObject(p->name), pmemAddr(NULL), port(NULL), lat(p->latency), _params(p)
{
-
- this->setFlags(AutoDelete);
-}
-
-void
-PhysicalMemory::MemResponseEvent::process()
-{
- memoryPort->sendTiming(pkt);
-}
-
-const char *
-PhysicalMemory::MemResponseEvent::description()
-{
- return "Physical Memory Timing Access respnse event";
-}
-
-PhysicalMemory::PhysicalMemory(const string &n, Tick latency)
- : MemObject(n),base_addr(0), pmem_addr(NULL), port(NULL), lat(latency)
-{
- // Hardcoded to 128 MB for now.
- pmem_size = 1 << 27;
-
- if (pmem_size % TheISA::PageBytes != 0)
+ if (params()->addrRange.size() % TheISA::PageBytes != 0)
panic("Memory Size not divisible by page size\n");
int map_flags = MAP_ANON | MAP_PRIVATE;
- pmem_addr = (uint8_t *)mmap(NULL, pmem_size, PROT_READ | PROT_WRITE,
+ pmemAddr = (uint8_t *)mmap(NULL, params()->addrRange.size(), PROT_READ | PROT_WRITE,
map_flags, -1, 0);
- if (pmem_addr == (void *)MAP_FAILED) {
+ if (pmemAddr == (void *)MAP_FAILED) {
perror("mmap");
fatal("Could not mmap!\n");
}
- page_ptr = 0;
+ pagePtr = 0;
}
void
PhysicalMemory::~PhysicalMemory()
{
- if (pmem_addr)
- munmap(pmem_addr, pmem_size);
+ if (pmemAddr)
+ munmap(pmemAddr, params()->addrRange.size());
//Remove memPorts?
}
Addr
PhysicalMemory::new_page()
{
- Addr return_addr = page_ptr << LogVMPageSize;
- return_addr += base_addr;
+ Addr return_addr = pagePtr << LogVMPageSize;
+ return_addr += params()->addrRange.start;
- ++page_ptr;
+ ++pagePtr;
return return_addr;
}
return 0;
}
-bool
-PhysicalMemory::doTimingAccess (Packet *pkt, MemoryPort* memoryPort)
+Tick
+PhysicalMemory::calculateLatency(PacketPtr pkt)
{
- doFunctionalAccess(pkt);
+ return lat;
+}
+
+
- // turn packet around to go back to requester
- pkt->makeTimingResponse();
- MemResponseEvent* response = new MemResponseEvent(pkt, memoryPort);
- response->schedule(curTick + lat);
+// 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)
+{
+ Addr paddr = LockedAddr::mask(req->getPaddr());
+
+ // first we check if we already have a locked addr for this
+ // xc. Since each xc only gets one, we just update the
+ // existing record with the new address.
+ list<LockedAddr>::iterator i;
+
+ 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);
+ i->addr = paddr;
+ return;
+ }
+ }
- return true;
+ // 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);
+ lockedAddrList.push_front(LockedAddr(req));
}
-Tick
-PhysicalMemory::doAtomicAccess(Packet *pkt)
+
+// Called on *writes* only... both regular stores and
+// store-conditional operations. Check for conventional stores which
+// conflict with locked addresses, and for success/failure of store
+// conditionals.
+bool
+PhysicalMemory::checkLockedAddrList(Request *req)
{
- doFunctionalAccess(pkt);
- pkt->time = curTick + lat;
- return curTick + lat;
+ Addr paddr = LockedAddr::mask(req->getPaddr());
+ bool isLocked = req->isLocked();
+
+ // Initialize return value. Non-conditional stores always
+ // succeed. Assume conditional stores will fail until proven
+ // otherwise.
+ bool success = !isLocked;
+
+ // Iterate over list. Note that there could be multiple matching
+ // records, as more than one context could have done a load locked
+ // to this location.
+ list<LockedAddr>::iterator i = lockedAddrList.begin();
+
+ while (i != lockedAddrList.end()) {
+
+ if (i->addr == paddr) {
+ // we have a matching address
+
+ if (isLocked && i->matchesContext(req)) {
+ // 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);
+ 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);
+ i = lockedAddrList.erase(i);
+ }
+ else {
+ // no match: advance to next record
+ ++i;
+ }
+ }
+
+ if (isLocked) {
+ req->setScResult(success ? 1 : 0);
+ }
+
+ return success;
}
void
-PhysicalMemory::doFunctionalAccess(Packet *pkt)
+PhysicalMemory::doFunctionalAccess(PacketPtr pkt)
{
- assert(pkt->getAddr() + pkt->getSize() < pmem_size);
+ assert(pkt->getAddr() + pkt->getSize() <= params()->addrRange.size());
- switch (pkt->cmd) {
- case Packet::ReadReq:
+ if (pkt->isRead()) {
+ if (pkt->req->isLocked()) {
+ trackLoadLocked(pkt->req);
+ }
+ DPRINTF(MemoryAccess, "Performing Read of size %i on address 0x%x\n",
+ pkt->getSize(), pkt->getAddr());
memcpy(pkt->getPtr<uint8_t>(),
- pmem_addr + pkt->getAddr() - base_addr,
+ pmemAddr + pkt->getAddr() - params()->addrRange.start,
pkt->getSize());
- break;
- case Packet::WriteReq:
- memcpy(pmem_addr + pkt->getAddr() - base_addr,
- pkt->getPtr<uint8_t>(),
- pkt->getSize());
- // temporary hack: will need to add real LL/SC implementation
- // for cacheless systems later.
- if (pkt->req->getFlags() & LOCKED) {
- pkt->req->setScResult(1);
+ }
+ else if (pkt->isWrite()) {
+ if (writeOK(pkt->req)) {
+ DPRINTF(MemoryAccess, "Performing Write of size %i on address 0x%x\n",
+ pkt->getSize(), pkt->getAddr());
+ memcpy(pmemAddr + pkt->getAddr() - params()->addrRange.start,
+ pkt->getPtr<uint8_t>(), pkt->getSize());
}
- break;
- default:
+ }
+ else if (pkt->isInvalidate()) {
+ //upgrade or invalidate
+ pkt->flags |= SATISFIED;
+ }
+ else {
panic("unimplemented");
}
}
Port *
-PhysicalMemory::getPort(const std::string &if_name)
+PhysicalMemory::getPort(const std::string &if_name, int idx)
{
- if (if_name == "") {
+ if (if_name == "port" && idx == -1) {
if (port != NULL)
panic("PhysicalMemory::getPort: additional port requested to memory!");
port = new MemoryPort(name() + "-port", this);
return port;
} else if (if_name == "functional") {
- /* special port for functional writes at startup. */
+ /* special port for functional writes at startup. And for memtester */
return new MemoryPort(name() + "-funcport", this);
} else {
panic("PhysicalMemory::getPort: unknown port %s requested", if_name);
PhysicalMemory::MemoryPort::MemoryPort(const std::string &_name,
PhysicalMemory *_memory)
- : Port(_name), memory(_memory)
+ : SimpleTimingPort(_name), memory(_memory)
{ }
void
{
snoop.clear();
resp.clear();
- resp.push_back(RangeSize(base_addr, pmem_size));
+ resp.push_back(RangeSize(params()->addrRange.start,
+ params()->addrRange.size()));
}
int
return memory->deviceBlockSize();
}
-bool
-PhysicalMemory::MemoryPort::recvTiming(Packet *pkt)
-{
- return memory->doTimingAccess(pkt, this);
-}
-
Tick
-PhysicalMemory::MemoryPort::recvAtomic(Packet *pkt)
+PhysicalMemory::MemoryPort::recvAtomic(PacketPtr pkt)
{
- return memory->doAtomicAccess(pkt);
+ memory->doFunctionalAccess(pkt);
+ return memory->calculateLatency(pkt);
}
void
-PhysicalMemory::MemoryPort::recvFunctional(Packet *pkt)
+PhysicalMemory::MemoryPort::recvFunctional(PacketPtr 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);
}
-
+unsigned int
+PhysicalMemory::drain(Event *de)
+{
+ int count = port->drain(de);
+ if (count)
+ changeState(Draining);
+ else
+ changeState(Drained);
+ return count;
+}
void
PhysicalMemory::serialize(ostream &os)
gzFile compressedMem;
string filename = name() + ".physmem";
- SERIALIZE_SCALAR(pmem_size);
SERIALIZE_SCALAR(filename);
// write memory file
fatal("Insufficient memory to allocate compression state for %s\n",
filename);
- if (gzwrite(compressedMem, pmem_addr, pmem_size) != pmem_size) {
+ if (gzwrite(compressedMem, pmemAddr, params()->addrRange.size()) != params()->addrRange.size()) {
fatal("Write failed on physical memory checkpoint file '%s'\n",
filename);
}
const int chunkSize = 16384;
- // unmap file that was mmaped in the constructor
- munmap(pmem_addr, pmem_size);
-
string filename;
- UNSERIALIZE_SCALAR(pmem_size);
UNSERIALIZE_SCALAR(filename);
filename = cp->cptDir + "/" + filename;
fatal("Insufficient memory to allocate compression state for %s\n",
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(pmemAddr, params()->addrRange.size());
- pmem_addr = (uint8_t *)mmap(NULL, pmem_size, PROT_READ | PROT_WRITE,
+ pmemAddr = (uint8_t *)mmap(NULL, params()->addrRange.size(), PROT_READ | PROT_WRITE,
MAP_ANON | MAP_PRIVATE, -1, 0);
- if (pmem_addr == (void *)MAP_FAILED) {
+ if (pmemAddr == (void *)MAP_FAILED) {
perror("mmap");
fatal("Could not mmap physical memory!\n");
}
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 < pmem_size) {
+ while (curSize < params()->addrRange.size()) {
bytesRead = gzread(compressedMem, tempPage, chunkSize);
- if (bytesRead != chunkSize && bytesRead != pmem_size - curSize)
+ if (bytesRead != chunkSize && bytesRead != params()->addrRange.size() - curSize)
fatal("Read failed on physical memory checkpoint file '%s'"
" got %d bytes, expected %d or %d bytes\n",
- filename, bytesRead, chunkSize, pmem_size-curSize);
+ filename, bytesRead, chunkSize, params()->addrRange.size()-curSize);
assert(bytesRead % sizeof(long) == 0);
for (int x = 0; x < bytesRead/sizeof(long); x++)
{
if (*(tempPage+x) != 0) {
- pmem_current = (long*)(pmem_addr + curSize + x * sizeof(long));
+ pmem_current = (long*)(pmemAddr + curSize + x * sizeof(long));
*pmem_current = *(tempPage+x);
}
}
CREATE_SIM_OBJECT(PhysicalMemory)
{
-
- return new PhysicalMemory(getInstanceName(), latency);
+ PhysicalMemory::Params *p = new PhysicalMemory::Params;
+ p->name = getInstanceName();
+ p->addrRange = range;
+ p->latency = latency;
+ return new PhysicalMemory(p);
}
REGISTER_SIM_OBJECT("PhysicalMemory", PhysicalMemory)