X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=src%2Fmem%2Fphysical.cc;h=0302f7351f9b31655a439aa62d51509ceac8eb09;hb=06482e6eeda9ba092c2fdc87217e391e64ff36a0;hp=26dbef0cde100e305c68da86e704f7e215f10fc2;hpb=5df77b865ddc29a00629a679437dee2578997559;p=gem5.git diff --git a/src/mem/physical.cc b/src/mem/physical.cc index 26dbef0cd..0302f7351 100644 --- a/src/mem/physical.cc +++ b/src/mem/physical.cc @@ -24,6 +24,9 @@ * 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 @@ -36,58 +39,33 @@ #include #include - +#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 @@ -100,18 +78,18 @@ PhysicalMemory::init() 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; } @@ -122,49 +100,122 @@ PhysicalMemory::deviceBlockSize() 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::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::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(), - 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(), - 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(), pkt->getSize()); } - break; - default: + } + else if (pkt->isInvalidate()) { + //upgrade or invalidate + pkt->flags |= SATISFIED; + } + else { panic("unimplemented"); } @@ -172,15 +223,15 @@ PhysicalMemory::doFunctionalAccess(Packet *pkt) } 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); @@ -194,7 +245,7 @@ PhysicalMemory::recvStatusChange(Port::Status status) PhysicalMemory::MemoryPort::MemoryPort(const std::string &_name, PhysicalMemory *_memory) - : Port(_name), memory(_memory) + : SimpleTimingPort(_name), memory(_memory) { } void @@ -215,7 +266,8 @@ PhysicalMemory::getAddressRanges(AddrRangeList &resp, AddrRangeList &snoop) { snoop.clear(); resp.clear(); - resp.push_back(RangeSize(base_addr, pmem_size)); + resp.push_back(RangeSize(params()->addrRange.start, + params()->addrRange.size())); } int @@ -224,25 +276,32 @@ PhysicalMemory::MemoryPort::deviceBlockSize() 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) @@ -250,7 +309,6 @@ PhysicalMemory::serialize(ostream &os) gzFile compressedMem; string filename = name() + ".physmem"; - SERIALIZE_SCALAR(pmem_size); SERIALIZE_SCALAR(filename); // write memory file @@ -266,7 +324,7 @@ PhysicalMemory::serialize(ostream &os) 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); } @@ -287,12 +345,8 @@ PhysicalMemory::unserialize(Checkpoint *cp, const string §ion) 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; @@ -309,11 +363,15 @@ PhysicalMemory::unserialize(Checkpoint *cp, const string §ion) 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"); } @@ -324,19 +382,19 @@ PhysicalMemory::unserialize(Checkpoint *cp, const string §ion) 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); } } @@ -370,8 +428,11 @@ END_INIT_SIM_OBJECT_PARAMS(PhysicalMemory) 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)