abstract_mem.cc revision 8719
13931Ssaidi@eecs.umich.edu/*
22632Sstever@eecs.umich.edu * Copyright (c) 2010-2011 ARM Limited
32632Sstever@eecs.umich.edu * All rights reserved
42632Sstever@eecs.umich.edu *
52632Sstever@eecs.umich.edu * The license below extends only to copyright in the software and shall
62632Sstever@eecs.umich.edu * not be construed as granting a license to any other intellectual
72632Sstever@eecs.umich.edu * property including but not limited to intellectual property relating
82632Sstever@eecs.umich.edu * to a hardware implementation of the functionality of the software
92632Sstever@eecs.umich.edu * licensed hereunder.  You may use the software subject to the license
102632Sstever@eecs.umich.edu * terms below provided that you ensure that this notice is replicated
112632Sstever@eecs.umich.edu * unmodified and in its entirety in all distributions of the software,
122632Sstever@eecs.umich.edu * modified or unmodified, in source code or in binary form.
132632Sstever@eecs.umich.edu *
142632Sstever@eecs.umich.edu * Copyright (c) 2001-2005 The Regents of The University of Michigan
152632Sstever@eecs.umich.edu * All rights reserved.
162632Sstever@eecs.umich.edu *
172632Sstever@eecs.umich.edu * Redistribution and use in source and binary forms, with or without
182632Sstever@eecs.umich.edu * modification, are permitted provided that the following conditions are
192632Sstever@eecs.umich.edu * met: redistributions of source code must retain the above copyright
202632Sstever@eecs.umich.edu * notice, this list of conditions and the following disclaimer;
212632Sstever@eecs.umich.edu * redistributions in binary form must reproduce the above copyright
222632Sstever@eecs.umich.edu * notice, this list of conditions and the following disclaimer in the
232632Sstever@eecs.umich.edu * documentation and/or other materials provided with the distribution;
242632Sstever@eecs.umich.edu * neither the name of the copyright holders nor the names of its
252632Sstever@eecs.umich.edu * contributors may be used to endorse or promote products derived from
262632Sstever@eecs.umich.edu * this software without specific prior written permission.
272632Sstever@eecs.umich.edu *
282632Sstever@eecs.umich.edu * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
292632Sstever@eecs.umich.edu * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
302632Sstever@eecs.umich.edu * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
312030SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
322030SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
332030SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
342030SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
352030SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
362030SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
372224SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
382482SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
392224SN/A *
402482SN/A * Authors: Ron Dreslinski
412482SN/A *          Ali Saidi
422482SN/A */
432482SN/A
442482SN/A#include <sys/mman.h>
452482SN/A#include <sys/types.h>
462482SN/A#include <sys/user.h>
472482SN/A#include <fcntl.h>
482458SN/A#include <unistd.h>
492224SN/A#include <zlib.h>
502482SN/A
512224SN/A#include <cerrno>
522224SN/A#include <cstdio>
532224SN/A#include <iostream>
542224SN/A#include <string>
552224SN/A
562224SN/A#include "arch/isa_traits.hh"
572224SN/A#include "arch/registers.hh"
582224SN/A#include "base/intmath.hh"
592224SN/A#include "base/misc.hh"
602224SN/A#include "base/random.hh"
612224SN/A#include "base/types.hh"
622224SN/A#include "config/full_system.hh"
632224SN/A#include "config/the_isa.hh"
642224SN/A#include "debug/LLSC.hh"
652224SN/A#include "debug/MemoryAccess.hh"
662224SN/A#include "mem/packet_access.hh"
672224SN/A#include "mem/physical.hh"
682458SN/A#include "sim/eventq.hh"
692224SN/A
704004Sgblack@eecs.umich.eduusing namespace std;
714004Sgblack@eecs.umich.eduusing namespace TheISA;
724004Sgblack@eecs.umich.edu
734004Sgblack@eecs.umich.eduPhysicalMemory::PhysicalMemory(const Params *p)
744004Sgblack@eecs.umich.edu    : MemObject(p), pmemAddr(NULL), lat(p->latency), lat_var(p->latency_var),
754004Sgblack@eecs.umich.edu      _size(params()->range.size()), _start(params()->range.start)
764004Sgblack@eecs.umich.edu{
774004Sgblack@eecs.umich.edu    if (size() % TheISA::PageBytes != 0)
784004Sgblack@eecs.umich.edu        panic("Memory Size not divisible by page size\n");
794004Sgblack@eecs.umich.edu
804004Sgblack@eecs.umich.edu    if (params()->null)
814004Sgblack@eecs.umich.edu        return;
824004Sgblack@eecs.umich.edu
834004Sgblack@eecs.umich.edu
844004Sgblack@eecs.umich.edu    if (params()->file == "") {
854004Sgblack@eecs.umich.edu        int map_flags = MAP_ANON | MAP_PRIVATE;
864004Sgblack@eecs.umich.edu        pmemAddr = (uint8_t *)mmap(NULL, size(),
874004Sgblack@eecs.umich.edu                                   PROT_READ | PROT_WRITE, map_flags, -1, 0);
884004Sgblack@eecs.umich.edu    } else {
894004Sgblack@eecs.umich.edu        int map_flags = MAP_PRIVATE;
905202Sstever@gmail.com        int fd = open(params()->file.c_str(), O_RDONLY);
912561SN/A        _size = lseek(fd, 0, SEEK_END);
922030SN/A        lseek(fd, 0, SEEK_SET);
932030SN/A        pmemAddr = (uint8_t *)mmap(NULL, roundUp(size(), sysconf(_SC_PAGESIZE)),
942030SN/A                                   PROT_READ | PROT_WRITE, map_flags, fd, 0);
952224SN/A    }
962030SN/A
972224SN/A    if (pmemAddr == (void *)MAP_FAILED) {
982224SN/A        perror("mmap");
992224SN/A        if (params()->file == "")
1003278Sgblack@eecs.umich.edu            fatal("Could not mmap!\n");
1012224SN/A        else
1022030SN/A            fatal("Could not find file: %s\n", params()->file);
1032030SN/A    }
1042030SN/A
1052224SN/A    //If requested, initialize all the memory to 0
1062224SN/A    if (p->zero)
1072469SN/A        memset(pmemAddr, 0, size());
1082951Sgblack@eecs.umich.edu}
1092944Sgblack@eecs.umich.edu
1102944Sgblack@eecs.umich.eduvoid
1112944Sgblack@eecs.umich.eduPhysicalMemory::init()
1122944Sgblack@eecs.umich.edu{
1132944Sgblack@eecs.umich.edu    if (ports.size() == 0) {
1147720Sgblack@eecs.umich.edu        fatal("PhysicalMemory object %s is unconnected!", name());
1157720Sgblack@eecs.umich.edu    }
1162030SN/A
1172030SN/A    for (PortIterator pi = ports.begin(); pi != ports.end(); ++pi) {
1184004Sgblack@eecs.umich.edu        if (*pi)
1194004Sgblack@eecs.umich.edu            (*pi)->sendRangeChange();
1202482SN/A    }
1212516SN/A}
1227741Sgblack@eecs.umich.edu
1237741Sgblack@eecs.umich.eduPhysicalMemory::~PhysicalMemory()
1242516SN/A{
1252526SN/A    if (pmemAddr)
1262516SN/A        munmap((char*)pmemAddr, size());
1272516SN/A}
1282482SN/A
1292482SN/Avoid
1302561SN/APhysicalMemory::regStats()
1312561SN/A{
1325202Sstever@gmail.com    using namespace Stats;
1332561SN/A
1347741Sgblack@eecs.umich.edu    bytesRead
1357741Sgblack@eecs.umich.edu        .name(name() + ".bytes_read")
1367741Sgblack@eecs.umich.edu        .desc("Number of bytes read from this memory")
1377741Sgblack@eecs.umich.edu        ;
1387741Sgblack@eecs.umich.edu    bytesInstRead
1397741Sgblack@eecs.umich.edu        .name(name() + ".bytes_inst_read")
1407741Sgblack@eecs.umich.edu        .desc("Number of instructions bytes read from this memory")
1417741Sgblack@eecs.umich.edu        ;
1427741Sgblack@eecs.umich.edu    bytesWritten
1437741Sgblack@eecs.umich.edu        .name(name() + ".bytes_written")
1447741Sgblack@eecs.umich.edu        .desc("Number of bytes written to this memory")
1457741Sgblack@eecs.umich.edu        ;
1467741Sgblack@eecs.umich.edu    numReads
1477741Sgblack@eecs.umich.edu        .name(name() + ".num_reads")
1487741Sgblack@eecs.umich.edu        .desc("Number of read requests responded to by this memory")
1497741Sgblack@eecs.umich.edu        ;
1502561SN/A    numWrites
1512561SN/A        .name(name() + ".num_writes")
1522561SN/A        .desc("Number of write requests responded to by this memory")
1532482SN/A        ;
1542482SN/A    numOther
1552482SN/A        .name(name() + ".num_other")
1562482SN/A        .desc("Number of other requests responded to by this memory")
1572482SN/A        ;
1582482SN/A    bwRead
1592482SN/A        .name(name() + ".bw_read")
1604362Sgblack@eecs.umich.edu        .desc("Total read bandwidth from this memory (bytes/s)")
1614362Sgblack@eecs.umich.edu        .precision(0)
1624362Sgblack@eecs.umich.edu        .prereq(bytesRead)
1634362Sgblack@eecs.umich.edu        ;
1644362Sgblack@eecs.umich.edu    bwInstRead
1654362Sgblack@eecs.umich.edu        .name(name() + ".bw_inst_read")
1664362Sgblack@eecs.umich.edu        .desc("Instruction read bandwidth from this memory (bytes/s)")
1674362Sgblack@eecs.umich.edu        .precision(0)
1684362Sgblack@eecs.umich.edu        .prereq(bytesInstRead)
1694362Sgblack@eecs.umich.edu        ;
1704362Sgblack@eecs.umich.edu    bwWrite
1714362Sgblack@eecs.umich.edu        .name(name() + ".bw_write")
1724362Sgblack@eecs.umich.edu        .desc("Write bandwidth from this memory (bytes/s)")
1734362Sgblack@eecs.umich.edu        .precision(0)
1744362Sgblack@eecs.umich.edu        .prereq(bytesWritten)
1754362Sgblack@eecs.umich.edu        ;
1764362Sgblack@eecs.umich.edu    bwTotal
1774362Sgblack@eecs.umich.edu        .name(name() + ".bw_total")
1784362Sgblack@eecs.umich.edu        .desc("Total bandwidth to/from this memory (bytes/s)")
1794362Sgblack@eecs.umich.edu        .precision(0)
1804362Sgblack@eecs.umich.edu        .prereq(bwTotal)
1814362Sgblack@eecs.umich.edu        ;
1824362Sgblack@eecs.umich.edu    bwRead = bytesRead / simSeconds;
1834362Sgblack@eecs.umich.edu    bwInstRead = bytesInstRead / simSeconds;
1848588Sgblack@eecs.umich.edu    bwWrite = bytesWritten / simSeconds;
1858588Sgblack@eecs.umich.edu    bwTotal = (bytesRead + bytesWritten) / simSeconds;
1868588Sgblack@eecs.umich.edu}
1874362Sgblack@eecs.umich.edu
1884362Sgblack@eecs.umich.eduunsigned
1894362Sgblack@eecs.umich.eduPhysicalMemory::deviceBlockSize() const
1904362Sgblack@eecs.umich.edu{
1914362Sgblack@eecs.umich.edu    //Can accept anysize request
1924362Sgblack@eecs.umich.edu    return 0;
1934362Sgblack@eecs.umich.edu}
1944362Sgblack@eecs.umich.edu
1954362Sgblack@eecs.umich.eduTick
1964362Sgblack@eecs.umich.eduPhysicalMemory::calculateLatency(PacketPtr pkt)
1974362Sgblack@eecs.umich.edu{
1984362Sgblack@eecs.umich.edu    Tick latency = lat;
1994362Sgblack@eecs.umich.edu    if (lat_var != 0)
2004362Sgblack@eecs.umich.edu        latency += random_mt.random<Tick>(0, lat_var);
2014362Sgblack@eecs.umich.edu    return latency;
2024362Sgblack@eecs.umich.edu}
2034362Sgblack@eecs.umich.edu
2044362Sgblack@eecs.umich.edu
2054362Sgblack@eecs.umich.edu
2064362Sgblack@eecs.umich.edu// Add load-locked to tracking list.  Should only be called if the
2074362Sgblack@eecs.umich.edu// operation is a load and the LLSC flag is set.
2084362Sgblack@eecs.umich.eduvoid
2094362Sgblack@eecs.umich.eduPhysicalMemory::trackLoadLocked(PacketPtr pkt)
2104362Sgblack@eecs.umich.edu{
2114362Sgblack@eecs.umich.edu    Request *req = pkt->req;
2124362Sgblack@eecs.umich.edu    Addr paddr = LockedAddr::mask(req->getPaddr());
2134362Sgblack@eecs.umich.edu
2144362Sgblack@eecs.umich.edu    // first we check if we already have a locked addr for this
2154362Sgblack@eecs.umich.edu    // xc.  Since each xc only gets one, we just update the
2164362Sgblack@eecs.umich.edu    // existing record with the new address.
2174362Sgblack@eecs.umich.edu    list<LockedAddr>::iterator i;
2184362Sgblack@eecs.umich.edu
2194362Sgblack@eecs.umich.edu    for (i = lockedAddrList.begin(); i != lockedAddrList.end(); ++i) {
2204362Sgblack@eecs.umich.edu        if (i->matchesContext(req)) {
2214362Sgblack@eecs.umich.edu            DPRINTF(LLSC, "Modifying lock record: context %d addr %#x\n",
2224362Sgblack@eecs.umich.edu                    req->contextId(), paddr);
2234362Sgblack@eecs.umich.edu            i->addr = paddr;
2244362Sgblack@eecs.umich.edu            return;
2254362Sgblack@eecs.umich.edu        }
2264362Sgblack@eecs.umich.edu    }
2274362Sgblack@eecs.umich.edu
2284362Sgblack@eecs.umich.edu    // no record for this xc: need to allocate a new one
2294362Sgblack@eecs.umich.edu    DPRINTF(LLSC, "Adding lock record: context %d addr %#x\n",
2302482SN/A            req->contextId(), paddr);
2312482SN/A    lockedAddrList.push_front(LockedAddr(req));
2328588Sgblack@eecs.umich.edu}
2332482SN/A
2342482SN/A
2352516SN/A// Called on *writes* only... both regular stores and
2362516SN/A// store-conditional operations.  Check for conventional stores which
2372614SN/A// conflict with locked addresses, and for success/failure of store
2382614SN/A// conditionals.
2392516SN/Abool
2402482SN/APhysicalMemory::checkLockedAddrList(PacketPtr pkt)
2412614SN/A{
2422482SN/A    Request *req = pkt->req;
2432516SN/A    Addr paddr = LockedAddr::mask(req->getPaddr());
2442030SN/A    bool isLLSC = pkt->isLLSC();
2452030SN/A
2462030SN/A    // Initialize return value.  Non-conditional stores always
2472030SN/A    // succeed.  Assume conditional stores will fail until proven
2482516SN/A    // otherwise.
2492516SN/A    bool success = !isLLSC;
2502516SN/A
2512516SN/A    // Iterate over list.  Note that there could be multiple matching
2522516SN/A    // records, as more than one context could have done a load locked
2532944Sgblack@eecs.umich.edu    // to this location.
2542944Sgblack@eecs.umich.edu    list<LockedAddr>::iterator i = lockedAddrList.begin();
2552944Sgblack@eecs.umich.edu
2567741Sgblack@eecs.umich.edu    while (i != lockedAddrList.end()) {
2572944Sgblack@eecs.umich.edu
2582944Sgblack@eecs.umich.edu        if (i->addr == paddr) {
2597741Sgblack@eecs.umich.edu            // we have a matching address
2602944Sgblack@eecs.umich.edu
2612944Sgblack@eecs.umich.edu            if (isLLSC && i->matchesContext(req)) {
2622944Sgblack@eecs.umich.edu                // it's a store conditional, and as far as the memory
2632944Sgblack@eecs.umich.edu                // system can tell, the requesting context's lock is
2642944Sgblack@eecs.umich.edu                // still valid.
2652469SN/A                DPRINTF(LLSC, "StCond success: context %d addr %#x\n",
2667720Sgblack@eecs.umich.edu                        req->contextId(), paddr);
2677720Sgblack@eecs.umich.edu                success = true;
2687720Sgblack@eecs.umich.edu            }
2697720Sgblack@eecs.umich.edu
2707720Sgblack@eecs.umich.edu            // Get rid of our record of this lock and advance to next
2717720Sgblack@eecs.umich.edu            DPRINTF(LLSC, "Erasing lock record: context %d addr %#x\n",
2722944Sgblack@eecs.umich.edu                    i->contextId, paddr);
2732944Sgblack@eecs.umich.edu            i = lockedAddrList.erase(i);
2747741Sgblack@eecs.umich.edu        }
2752944Sgblack@eecs.umich.edu        else {
2762944Sgblack@eecs.umich.edu            // no match: advance to next record
2772944Sgblack@eecs.umich.edu            ++i;
2782944Sgblack@eecs.umich.edu        }
2792944Sgblack@eecs.umich.edu    }
2802944Sgblack@eecs.umich.edu
2817741Sgblack@eecs.umich.edu    if (isLLSC) {
2822944Sgblack@eecs.umich.edu        req->setExtraData(success ? 1 : 0);
2832944Sgblack@eecs.umich.edu    }
2842944Sgblack@eecs.umich.edu
2852944Sgblack@eecs.umich.edu    return success;
2862951Sgblack@eecs.umich.edu}
2872469SN/A
2882516SN/A
2892516SN/A#if TRACING_ON
2902516SN/A
2912516SN/A#define CASE(A, T)                                                      \
2923978Sgblack@eecs.umich.edu  case sizeof(T):                                                       \
2939918Ssteve.reinhardt@amd.com    DPRINTF(MemoryAccess,"%s of size %i on address 0x%x data 0x%x\n",   \
2947741Sgblack@eecs.umich.edu            A, pkt->getSize(), pkt->getAddr(), pkt->get<T>());          \
2957741Sgblack@eecs.umich.edu  break
2963978Sgblack@eecs.umich.edu
2973978Sgblack@eecs.umich.edu
2983978Sgblack@eecs.umich.edu#define TRACE_PACKET(A)                                                 \
2993978Sgblack@eecs.umich.edu    do {                                                                \
3003978Sgblack@eecs.umich.edu        switch (pkt->getSize()) {                                       \
3013978Sgblack@eecs.umich.edu          CASE(A, uint64_t);                                            \
3027741Sgblack@eecs.umich.edu          CASE(A, uint32_t);                                            \
3033978Sgblack@eecs.umich.edu          CASE(A, uint16_t);                                            \
3047741Sgblack@eecs.umich.edu          CASE(A, uint8_t);                                             \
3053978Sgblack@eecs.umich.edu          default:                                                      \
3067741Sgblack@eecs.umich.edu            DPRINTF(MemoryAccess, "%s of size %i on address 0x%x\n",    \
3073978Sgblack@eecs.umich.edu                    A, pkt->getSize(), pkt->getAddr());                 \
3087741Sgblack@eecs.umich.edu            DDUMP(MemoryAccess, pkt->getPtr<uint8_t>(), pkt->getSize());\
3093978Sgblack@eecs.umich.edu        }                                                               \
3107741Sgblack@eecs.umich.edu    } while (0)
3113978Sgblack@eecs.umich.edu
3127741Sgblack@eecs.umich.edu#else
3133978Sgblack@eecs.umich.edu
3143978Sgblack@eecs.umich.edu#define TRACE_PACKET(A)
3153978Sgblack@eecs.umich.edu
3163978Sgblack@eecs.umich.edu#endif
3173978Sgblack@eecs.umich.edu
3183978Sgblack@eecs.umich.eduTick
3193978Sgblack@eecs.umich.eduPhysicalMemory::doAtomicAccess(PacketPtr pkt)
3203978Sgblack@eecs.umich.edu{
3213978Sgblack@eecs.umich.edu    assert(pkt->getAddr() >= start() &&
3223978Sgblack@eecs.umich.edu           pkt->getAddr() + pkt->getSize() <= start() + size());
3233978Sgblack@eecs.umich.edu
3243978Sgblack@eecs.umich.edu    if (pkt->memInhibitAsserted()) {
3253978Sgblack@eecs.umich.edu        DPRINTF(MemoryAccess, "mem inhibited on 0x%x: not responding\n",
3263978Sgblack@eecs.umich.edu                pkt->getAddr());
3273978Sgblack@eecs.umich.edu        return 0;
3283978Sgblack@eecs.umich.edu    }
3293978Sgblack@eecs.umich.edu
3303978Sgblack@eecs.umich.edu    uint8_t *hostAddr = pmemAddr + pkt->getAddr() - start();
3313978Sgblack@eecs.umich.edu
3323978Sgblack@eecs.umich.edu    if (pkt->cmd == MemCmd::SwapReq) {
3333978Sgblack@eecs.umich.edu        IntReg overwrite_val;
3343978Sgblack@eecs.umich.edu        bool overwrite_mem;
3353978Sgblack@eecs.umich.edu        uint64_t condition_val64;
3363978Sgblack@eecs.umich.edu        uint32_t condition_val32;
3373978Sgblack@eecs.umich.edu
3389918Ssteve.reinhardt@amd.com        if (!pmemAddr)
3399918Ssteve.reinhardt@amd.com            panic("Swap only works if there is real memory (i.e. null=False)");
3403978Sgblack@eecs.umich.edu        assert(sizeof(IntReg) >= pkt->getSize());
3419918Ssteve.reinhardt@amd.com
3423978Sgblack@eecs.umich.edu        overwrite_mem = true;
3433978Sgblack@eecs.umich.edu        // keep a copy of our possible write value, and copy what is at the
3443978Sgblack@eecs.umich.edu        // memory address into the packet
3453978Sgblack@eecs.umich.edu        std::memcpy(&overwrite_val, pkt->getPtr<uint8_t>(), pkt->getSize());
3463978Sgblack@eecs.umich.edu        std::memcpy(pkt->getPtr<uint8_t>(), hostAddr, pkt->getSize());
3473978Sgblack@eecs.umich.edu
3483978Sgblack@eecs.umich.edu        if (pkt->req->isCondSwap()) {
3493978Sgblack@eecs.umich.edu            if (pkt->getSize() == sizeof(uint64_t)) {
3503978Sgblack@eecs.umich.edu                condition_val64 = pkt->req->getExtraData();
3513978Sgblack@eecs.umich.edu                overwrite_mem = !std::memcmp(&condition_val64, hostAddr,
3523978Sgblack@eecs.umich.edu                                             sizeof(uint64_t));
3533978Sgblack@eecs.umich.edu            } else if (pkt->getSize() == sizeof(uint32_t)) {
3543978Sgblack@eecs.umich.edu                condition_val32 = (uint32_t)pkt->req->getExtraData();
3553978Sgblack@eecs.umich.edu                overwrite_mem = !std::memcmp(&condition_val32, hostAddr,
3563978Sgblack@eecs.umich.edu                                             sizeof(uint32_t));
3573978Sgblack@eecs.umich.edu            } else
3583978Sgblack@eecs.umich.edu                panic("Invalid size for conditional read/write\n");
3593978Sgblack@eecs.umich.edu        }
3603978Sgblack@eecs.umich.edu
3613978Sgblack@eecs.umich.edu        if (overwrite_mem)
3623978Sgblack@eecs.umich.edu            std::memcpy(hostAddr, &overwrite_val, pkt->getSize());
3633978Sgblack@eecs.umich.edu
3643978Sgblack@eecs.umich.edu        assert(!pkt->req->isInstFetch());
3653978Sgblack@eecs.umich.edu        TRACE_PACKET("Read/Write");
3663978Sgblack@eecs.umich.edu        numOther++;
3673978Sgblack@eecs.umich.edu    } else if (pkt->isRead()) {
3683978Sgblack@eecs.umich.edu        assert(!pkt->isWrite());
3693978Sgblack@eecs.umich.edu        if (pkt->isLLSC()) {
3703978Sgblack@eecs.umich.edu            trackLoadLocked(pkt);
3713978Sgblack@eecs.umich.edu        }
3723978Sgblack@eecs.umich.edu        if (pmemAddr)
3733978Sgblack@eecs.umich.edu            memcpy(pkt->getPtr<uint8_t>(), hostAddr, pkt->getSize());
3743978Sgblack@eecs.umich.edu        TRACE_PACKET(pkt->req->isInstFetch() ? "IFetch" : "Read");
3753978Sgblack@eecs.umich.edu        numReads++;
3763978Sgblack@eecs.umich.edu        bytesRead += pkt->getSize();
3773978Sgblack@eecs.umich.edu        if (pkt->req->isInstFetch())
3783978Sgblack@eecs.umich.edu            bytesInstRead += pkt->getSize();
3793978Sgblack@eecs.umich.edu    } else if (pkt->isWrite()) {
3803978Sgblack@eecs.umich.edu        if (writeOK(pkt)) {
3813978Sgblack@eecs.umich.edu            if (pmemAddr)
3823978Sgblack@eecs.umich.edu                memcpy(hostAddr, pkt->getPtr<uint8_t>(), pkt->getSize());
3833978Sgblack@eecs.umich.edu            assert(!pkt->req->isInstFetch());
3843978Sgblack@eecs.umich.edu            TRACE_PACKET("Write");
3853978Sgblack@eecs.umich.edu            numWrites++;
3863978Sgblack@eecs.umich.edu            bytesWritten += pkt->getSize();
3873978Sgblack@eecs.umich.edu        }
3883978Sgblack@eecs.umich.edu    } else if (pkt->isInvalidate()) {
3893978Sgblack@eecs.umich.edu        //upgrade or invalidate
3903978Sgblack@eecs.umich.edu        if (pkt->needsResponse()) {
3913978Sgblack@eecs.umich.edu            pkt->makeAtomicResponse();
3923978Sgblack@eecs.umich.edu        }
3933978Sgblack@eecs.umich.edu    } else {
3943978Sgblack@eecs.umich.edu        panic("unimplemented");
3953978Sgblack@eecs.umich.edu    }
3963978Sgblack@eecs.umich.edu
3973978Sgblack@eecs.umich.edu    if (pkt->needsResponse()) {
3983978Sgblack@eecs.umich.edu        pkt->makeAtomicResponse();
3993978Sgblack@eecs.umich.edu    }
4003978Sgblack@eecs.umich.edu    return calculateLatency(pkt);
4013978Sgblack@eecs.umich.edu}
4023978Sgblack@eecs.umich.edu
4033978Sgblack@eecs.umich.edu
4043978Sgblack@eecs.umich.eduvoid
4053978Sgblack@eecs.umich.eduPhysicalMemory::doFunctionalAccess(PacketPtr pkt)
4063978Sgblack@eecs.umich.edu{
4073978Sgblack@eecs.umich.edu    assert(pkt->getAddr() >= start() &&
4083978Sgblack@eecs.umich.edu           pkt->getAddr() + pkt->getSize() <= start() + size());
4093978Sgblack@eecs.umich.edu
4103978Sgblack@eecs.umich.edu
4113978Sgblack@eecs.umich.edu    uint8_t *hostAddr = pmemAddr + pkt->getAddr() - start();
4123978Sgblack@eecs.umich.edu
4133978Sgblack@eecs.umich.edu    if (pkt->isRead()) {
4143978Sgblack@eecs.umich.edu        if (pmemAddr)
4153978Sgblack@eecs.umich.edu            memcpy(pkt->getPtr<uint8_t>(), hostAddr, pkt->getSize());
4163978Sgblack@eecs.umich.edu        TRACE_PACKET("Read");
4173978Sgblack@eecs.umich.edu        pkt->makeAtomicResponse();
4183978Sgblack@eecs.umich.edu    } else if (pkt->isWrite()) {
4193978Sgblack@eecs.umich.edu        if (pmemAddr)
4203978Sgblack@eecs.umich.edu            memcpy(hostAddr, pkt->getPtr<uint8_t>(), pkt->getSize());
4213978Sgblack@eecs.umich.edu        TRACE_PACKET("Write");
4223978Sgblack@eecs.umich.edu        pkt->makeAtomicResponse();
4233978Sgblack@eecs.umich.edu    } else if (pkt->isPrint()) {
4243978Sgblack@eecs.umich.edu        Packet::PrintReqState *prs =
4253978Sgblack@eecs.umich.edu            dynamic_cast<Packet::PrintReqState*>(pkt->senderState);
4263978Sgblack@eecs.umich.edu        // Need to call printLabels() explicitly since we're not going
4273978Sgblack@eecs.umich.edu        // through printObj().
4283978Sgblack@eecs.umich.edu        prs->printLabels();
4293978Sgblack@eecs.umich.edu        // Right now we just print the single byte at the specified address.
4303978Sgblack@eecs.umich.edu        ccprintf(prs->os, "%s%#x\n", prs->curPrefix(), *hostAddr);
4313978Sgblack@eecs.umich.edu    } else {
4323978Sgblack@eecs.umich.edu        panic("PhysicalMemory: unimplemented functional command %s",
4339918Ssteve.reinhardt@amd.com              pkt->cmdString());
4343978Sgblack@eecs.umich.edu    }
4352469SN/A}
4362469SN/A
4372469SN/A
4387741Sgblack@eecs.umich.eduPort *
4397741Sgblack@eecs.umich.eduPhysicalMemory::getPort(const std::string &if_name, int idx)
4407741Sgblack@eecs.umich.edu{
4412030SN/A    if (if_name != "port") {
4422224SN/A        panic("PhysicalMemory::getPort: unknown port %s requested", if_name);
4432030SN/A    }
4442516SN/A
4452030SN/A    if (idx >= (int)ports.size()) {
4462224SN/A        ports.resize(idx + 1);
4472224SN/A    }
4482224SN/A
4497741Sgblack@eecs.umich.edu    if (ports[idx] != NULL) {
4502224SN/A        panic("PhysicalMemory::getPort: port %d already assigned", idx);
4517741Sgblack@eecs.umich.edu    }
4522224SN/A
4532224SN/A    MemoryPort *port =
4542224SN/A        new MemoryPort(csprintf("%s-port%d", name(), idx), this);
4552224SN/A
4562224SN/A    ports[idx] = port;
4572224SN/A    return port;
4587741Sgblack@eecs.umich.edu}
4597741Sgblack@eecs.umich.edu
4602224SN/APhysicalMemory::MemoryPort::MemoryPort(const std::string &_name,
4612224SN/A                                       PhysicalMemory *_memory)
4622224SN/A    : SimpleTimingPort(_name, _memory), memory(_memory)
4632030SN/A{ }
4642224SN/A
4652030SN/Avoid
4662030SN/APhysicalMemory::MemoryPort::recvRangeChange()
4677741Sgblack@eecs.umich.edu{
4687741Sgblack@eecs.umich.edu    // memory is a slave and thus should never have to worry about its
4694004Sgblack@eecs.umich.edu    // neighbours address ranges
4704004Sgblack@eecs.umich.edu}
4714004Sgblack@eecs.umich.edu
4724004Sgblack@eecs.umich.eduAddrRangeList
4734004Sgblack@eecs.umich.eduPhysicalMemory::MemoryPort::getAddrRanges()
4747741Sgblack@eecs.umich.edu{
4754004Sgblack@eecs.umich.edu    return memory->getAddrRanges();
4764004Sgblack@eecs.umich.edu}
4774004Sgblack@eecs.umich.edu
4784004Sgblack@eecs.umich.eduAddrRangeList
4794004Sgblack@eecs.umich.eduPhysicalMemory::getAddrRanges()
4804004Sgblack@eecs.umich.edu{
4814004Sgblack@eecs.umich.edu    AddrRangeList ranges;
4824004Sgblack@eecs.umich.edu    ranges.push_back(RangeSize(start(), size()));
4834004Sgblack@eecs.umich.edu    return ranges;
4844004Sgblack@eecs.umich.edu}
4854004Sgblack@eecs.umich.edu
4864004Sgblack@eecs.umich.eduunsigned
4874004Sgblack@eecs.umich.eduPhysicalMemory::MemoryPort::deviceBlockSize() const
4884004Sgblack@eecs.umich.edu{
4894004Sgblack@eecs.umich.edu    return memory->deviceBlockSize();
4904004Sgblack@eecs.umich.edu}
4914004Sgblack@eecs.umich.edu
4924004Sgblack@eecs.umich.eduTick
4934004Sgblack@eecs.umich.eduPhysicalMemory::MemoryPort::recvAtomic(PacketPtr pkt)
4944004Sgblack@eecs.umich.edu{
4954004Sgblack@eecs.umich.edu    return memory->doAtomicAccess(pkt);
4964004Sgblack@eecs.umich.edu}
4974004Sgblack@eecs.umich.edu
4984004Sgblack@eecs.umich.eduvoid
4994004Sgblack@eecs.umich.eduPhysicalMemory::MemoryPort::recvFunctional(PacketPtr pkt)
5004004Sgblack@eecs.umich.edu{
5014004Sgblack@eecs.umich.edu    pkt->pushLabel(memory->name());
5024004Sgblack@eecs.umich.edu
5034004Sgblack@eecs.umich.edu    if (!checkFunctional(pkt)) {
5044004Sgblack@eecs.umich.edu        // Default implementation of SimpleTimingPort::recvFunctional()
5054004Sgblack@eecs.umich.edu        // calls recvAtomic() and throws away the latency; we can save a
5064004Sgblack@eecs.umich.edu        // little here by just not calculating the latency.
5074004Sgblack@eecs.umich.edu        memory->doFunctionalAccess(pkt);
5084004Sgblack@eecs.umich.edu    }
5094004Sgblack@eecs.umich.edu
5104004Sgblack@eecs.umich.edu    pkt->popLabel();
5114004Sgblack@eecs.umich.edu}
5127741Sgblack@eecs.umich.edu
5137741Sgblack@eecs.umich.eduunsigned int
5142030SN/APhysicalMemory::drain(Event *de)
5152482SN/A{
5163603Ssaidi@eecs.umich.edu    int count = 0;
5173603Ssaidi@eecs.umich.edu    for (PortIterator pi = ports.begin(); pi != ports.end(); ++pi) {
5183603Ssaidi@eecs.umich.edu        count += (*pi)->drain(de);
5193603Ssaidi@eecs.umich.edu    }
5203603Ssaidi@eecs.umich.edu
5213603Ssaidi@eecs.umich.edu    if (count)
5227741Sgblack@eecs.umich.edu        changeState(Draining);
5232224SN/A    else
5242224SN/A        changeState(Drained);
5252224SN/A    return count;
5262224SN/A}
5272224SN/A
5282482SN/Avoid
5292224SN/APhysicalMemory::serialize(ostream &os)
5302482SN/A{
5312224SN/A    if (!pmemAddr)
5322482SN/A        return;
5332224SN/A
5342482SN/A    gzFile compressedMem;
5352224SN/A    string filename = name() + ".physmem";
5362482SN/A
5372224SN/A    SERIALIZE_SCALAR(filename);
5382482SN/A    SERIALIZE_SCALAR(_size);
5392224SN/A
5402482SN/A    // write memory file
5412224SN/A    string thefile = Checkpoint::dir() + "/" + filename.c_str();
5422482SN/A    int fd = creat(thefile.c_str(), 0664);
5432224SN/A    if (fd < 0) {
5442482SN/A        perror("creat");
5452224SN/A        fatal("Can't open physical memory checkpoint file '%s'\n", filename);
5462482SN/A    }
5472224SN/A
5482482SN/A    compressedMem = gzdopen(fd, "wb");
5492224SN/A    if (compressedMem == NULL)
5502482SN/A        fatal("Insufficient memory to allocate compression state for %s\n",
5512224SN/A                filename);
5522482SN/A
5532224SN/A    if (gzwrite(compressedMem, pmemAddr, size()) != (int)size()) {
5542482SN/A        fatal("Write failed on physical memory checkpoint file '%s'\n",
5552224SN/A              filename);
5562469SN/A    }
5572469SN/A
5582030SN/A    if (gzclose(compressedMem))
5592030SN/A        fatal("Close failed on physical memory checkpoint file '%s'\n",
5602030SN/A              filename);
5613931Ssaidi@eecs.umich.edu
5623931Ssaidi@eecs.umich.edu    list<LockedAddr>::iterator i = lockedAddrList.begin();
5638565Sgblack@eecs.umich.edu
5643931Ssaidi@eecs.umich.edu    vector<Addr> lal_addr;
5653931Ssaidi@eecs.umich.edu    vector<int> lal_cid;
5668565Sgblack@eecs.umich.edu    while (i != lockedAddrList.end()) {
56710196SCurtis.Dunham@arm.com        lal_addr.push_back(i->addr);
5683931Ssaidi@eecs.umich.edu        lal_cid.push_back(i->contextId);
5698738Sgblack@eecs.umich.edu        i++;
5708829Sgblack@eecs.umich.edu    }
5718829Sgblack@eecs.umich.edu    arrayParamOut(os, "lal_addr", lal_addr);
5728565Sgblack@eecs.umich.edu    arrayParamOut(os, "lal_cid", lal_cid);
5738565Sgblack@eecs.umich.edu}
57410474Sandreas.hansson@arm.com
5758565Sgblack@eecs.umich.eduvoid
5768565Sgblack@eecs.umich.eduPhysicalMemory::unserialize(Checkpoint *cp, const string &section)
5773931Ssaidi@eecs.umich.edu{
5787741Sgblack@eecs.umich.edu    if (!pmemAddr)
5793931Ssaidi@eecs.umich.edu        return;
5803931Ssaidi@eecs.umich.edu
5813931Ssaidi@eecs.umich.edu    gzFile compressedMem;
5823931Ssaidi@eecs.umich.edu    long *tempPage;
583    long *pmem_current;
584    uint64_t curSize;
585    uint32_t bytesRead;
586    const uint32_t chunkSize = 16384;
587
588    string filename;
589
590    UNSERIALIZE_SCALAR(filename);
591
592    filename = cp->cptDir + "/" + filename;
593
594    // mmap memoryfile
595    int fd = open(filename.c_str(), O_RDONLY);
596    if (fd < 0) {
597        perror("open");
598        fatal("Can't open physical memory checkpoint file '%s'", filename);
599    }
600
601    compressedMem = gzdopen(fd, "rb");
602    if (compressedMem == NULL)
603        fatal("Insufficient memory to allocate compression state for %s\n",
604                filename);
605
606    // unmap file that was mmapped in the constructor
607    // This is done here to make sure that gzip and open don't muck with our
608    // nice large space of memory before we reallocate it
609    munmap((char*)pmemAddr, size());
610
611    UNSERIALIZE_SCALAR(_size);
612    if (size() > params()->range.size())
613        fatal("Memory size has changed! size %lld, param size %lld\n",
614              size(), params()->range.size());
615
616    pmemAddr = (uint8_t *)mmap(NULL, size(),
617        PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0);
618
619    if (pmemAddr == (void *)MAP_FAILED) {
620        perror("mmap");
621        fatal("Could not mmap physical memory!\n");
622    }
623
624    curSize = 0;
625    tempPage = (long*)malloc(chunkSize);
626    if (tempPage == NULL)
627        fatal("Unable to malloc memory to read file %s\n", filename);
628
629    /* Only copy bytes that are non-zero, so we don't give the VM system hell */
630    while (curSize < size()) {
631        bytesRead = gzread(compressedMem, tempPage, chunkSize);
632        if (bytesRead == 0)
633            break;
634
635        assert(bytesRead % sizeof(long) == 0);
636
637        for (uint32_t x = 0; x < bytesRead / sizeof(long); x++)
638        {
639             if (*(tempPage+x) != 0) {
640                 pmem_current = (long*)(pmemAddr + curSize + x * sizeof(long));
641                 *pmem_current = *(tempPage+x);
642             }
643        }
644        curSize += bytesRead;
645    }
646
647    free(tempPage);
648
649    if (gzclose(compressedMem))
650        fatal("Close failed on physical memory checkpoint file '%s'\n",
651              filename);
652
653    vector<Addr> lal_addr;
654    vector<int> lal_cid;
655    arrayParamIn(cp, section, "lal_addr", lal_addr);
656    arrayParamIn(cp, section, "lal_cid", lal_cid);
657    for(int i = 0; i < lal_addr.size(); i++)
658        lockedAddrList.push_front(LockedAddr(lal_addr[i], lal_cid[i]));
659}
660
661PhysicalMemory *
662PhysicalMemoryParams::create()
663{
664    return new PhysicalMemory(this);
665}
666