⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 bus.cc

📁 M5,一个功能强大的多处理器系统模拟器.很多针对处理器架构,性能的研究都使用它作为模拟平台
💻 CC
📖 第 1 页 / 共 2 页
字号:
/* * Copyright (c) 2006 * The Regents of The University of Michigan * All Rights Reserved * * This code is part of the M5 simulator. * * Permission is granted to use, copy, create derivative works and * redistribute this software and such derivative works for any * purpose, so long as the copyright notice above, this grant of * permission, and the disclaimer below appear in all copies made; and * so long as the name of The University of Michigan is not used in * any advertising or publicity pertaining to the use or distribution * of this software without specific, written prior authorization. * * THIS SOFTWARE IS PROVIDED AS IS, WITHOUT REPRESENTATION FROM THE * UNIVERSITY OF MICHIGAN AS TO ITS FITNESS FOR ANY PURPOSE, AND * WITHOUT WARRANTY BY THE UNIVERSITY OF MICHIGAN OF ANY KIND, EITHER * EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE. THE REGENTS OF THE UNIVERSITY OF MICHIGAN SHALL NOT BE * LIABLE FOR ANY DAMAGES, INCLUDING DIRECT, SPECIAL, INDIRECT, * INCIDENTAL, OR CONSEQUENTIAL DAMAGES, WITH RESPECT TO ANY CLAIM * ARISING OUT OF OR IN CONNECTION WITH THE USE OF THE SOFTWARE, EVEN * IF IT HAS BEEN OR IS HEREAFTER ADVISED OF THE POSSIBILITY OF SUCH * DAMAGES. * * Authors: Ali G. Saidi *//** * @file * Definition of a bus object. */#include <algorithm>#include <limits>#include "base/misc.hh"#include "base/trace.hh"#include "mem/bus.hh"Port *Bus::getPort(const std::string &if_name, int idx){    if (if_name == "default") {        if (defaultPort == NULL) {            defaultPort = new BusPort(csprintf("%s-default",name()), this,                                      defaultId);            cachedBlockSizeValid = false;            return defaultPort;        } else            fatal("Default port already set\n");    }    int id;    if (if_name == "functional") {        if (!funcPort) {            id = maxId++;            funcPort = new BusPort(csprintf("%s-p%d-func", name(), id), this, id);            funcPortId = id;            interfaces[id] = funcPort;        }        return funcPort;    }    // if_name ignored?  forced to be empty?    id = maxId++;    assert(maxId < std::numeric_limits<typeof(maxId)>::max());    BusPort *bp = new BusPort(csprintf("%s-p%d", name(), id), this, id);    interfaces[id] = bp;    cachedBlockSizeValid = false;    return bp;}voidBus::deletePortRefs(Port *p){    BusPort *bp =  dynamic_cast<BusPort*>(p);    if (bp == NULL)        panic("Couldn't convert Port* to BusPort*\n");    // If this is our one functional port    if (funcPort == bp)        return;    interfaces.erase(bp->getId());    clearBusCache();    delete bp;}/** Get the ranges of anyone other buses that we are connected to. */voidBus::init(){    m5::hash_map<short,BusPort*>::iterator intIter;    for (intIter = interfaces.begin(); intIter != interfaces.end(); intIter++)        intIter->second->sendStatusChange(Port::RangeChange);}Bus::BusFreeEvent::BusFreeEvent(Bus *_bus) : Event(&mainEventQueue), bus(_bus){}void Bus::BusFreeEvent::process(){    bus->recvRetry(-1);}const char * Bus::BusFreeEvent::description() const{    return "bus became available";}void Bus::preparePacket(PacketPtr pkt, Tick & headerTime){    //Bring tickNextIdle up to the present tick    //There is some potential ambiguity where a cycle starts, which might make    //a difference when devices are acting right around a cycle boundary. Using    //a < allows things which happen exactly on a cycle boundary to take up    //only the following cycle. Anything that happens later will have to "wait"    //for the end of that cycle, and then start using the bus after that.    if (tickNextIdle < curTick) {        tickNextIdle = curTick;        if (tickNextIdle % clock != 0)            tickNextIdle = curTick - (curTick % clock) + clock;    }    headerTime = tickNextIdle + headerCycles * clock;    // The packet will be sent. Figure out how long it occupies the bus, and    // how much of that time is for the first "word", aka bus width.    int numCycles = 0;    if (pkt->hasData()) {        // If a packet has data, it needs ceil(size/width) cycles to send it        int dataSize = pkt->getSize();        numCycles += dataSize/width;        if (dataSize % width)            numCycles++;    }    // The first word will be delivered after the current tick, the delivery    // of the address if any, and one bus cycle to deliver the data    pkt->firstWordTime = headerTime + clock;    pkt->finishTime = headerTime + numCycles * clock;}void Bus::occupyBus(Tick until){    tickNextIdle = until;    if (!busIdle.scheduled()) {        busIdle.schedule(tickNextIdle);    } else {        busIdle.reschedule(tickNextIdle);    }    DPRINTF(Bus, "The bus is now occupied from tick %d to %d\n",            curTick, tickNextIdle);}/** Function called by the port when the bus is receiving a Timing * transaction.*/boolBus::recvTiming(PacketPtr pkt){    short src = pkt->getSrc();    BusPort *src_port;    if (src == defaultId)        src_port = defaultPort;    else {        src_port = checkBusCache(src);        if (src_port == NULL) {            src_port = interfaces[src];            updateBusCache(src, src_port);        }    }    // If the bus is busy, or other devices are in line ahead of the current    // one, put this device on the retry list.    if (!pkt->isExpressSnoop() &&        (tickNextIdle > curTick ||         (retryList.size() && (!inRetry || src_port != retryList.front()))))    {        addToRetryList(src_port);        DPRINTF(Bus, "recvTiming: src %d dst %d %s 0x%x BUSY\n",                src, pkt->getDest(), pkt->cmdString(), pkt->getAddr());        return false;    }    DPRINTF(Bus, "recvTiming: src %d dst %d %s 0x%x\n",            src, pkt->getDest(), pkt->cmdString(), pkt->getAddr());    Tick headerTime = 0;    if (!pkt->isExpressSnoop()) {        preparePacket(pkt, headerTime);    }    short dest = pkt->getDest();    int dest_port_id;    Port *dest_port;    if (dest == Packet::Broadcast) {        dest_port_id = findPort(pkt->getAddr());        dest_port = (dest_port_id == defaultId) ?            defaultPort : interfaces[dest_port_id];        SnoopIter s_end = snoopPorts.end();        for (SnoopIter s_iter = snoopPorts.begin(); s_iter != s_end; s_iter++) {            BusPort *p = *s_iter;            if (p != dest_port && p != src_port) {                // cache is not allowed to refuse snoop                bool success M5_VAR_USED = p->sendTiming(pkt);                assert(success);            }        }    } else {        assert(dest >= 0 && dest < maxId);        assert(dest != src); // catch infinite loops        dest_port_id = dest;        if (dest_port_id == defaultId)            dest_port = defaultPort;        else {            dest_port = checkBusCache(dest);            if (dest_port == NULL) {                dest_port = interfaces[dest_port_id];	    // updateBusCache(dest_port_id, dest_port);            }        }        dest_port = (dest_port_id == defaultId) ?            defaultPort : interfaces[dest_port_id];    }    if (dest_port_id == src) {        // Must be forwarded snoop up from below...        assert(dest == Packet::Broadcast);        assert(src != defaultId); // catch infinite loops    } else {        // send to actual target        if (!dest_port->sendTiming(pkt))  {            // Packet not successfully sent. Leave or put it on the retry list.            // illegal to block responses... can lead to deadlock            assert(!pkt->isResponse());            DPRINTF(Bus, "recvTiming: src %d dst %d %s 0x%x TGT RETRY\n",                    src, pkt->getDest(), pkt->cmdString(), pkt->getAddr());            addToRetryList(src_port);            if (!pkt->isExpressSnoop()) {                occupyBus(headerTime);            }            return false;        }        // send OK, fall through    }    if (!pkt->isExpressSnoop()) {        occupyBus(pkt->finishTime);    }    // Packet was successfully sent.    // Also take care of retries    if (inRetry) {        DPRINTF(Bus, "Remove retry from list %d\n", src);        retryList.front()->onRetryList(false);        retryList.pop_front();        inRetry = false;    }    return true;}voidBus::recvRetry(int id){    // If there's anything waiting, and the bus isn't busy...    if (retryList.size() && curTick >= tickNextIdle) {        //retryingPort = retryList.front();        inRetry = true;        DPRINTF(Bus, "Sending a retry to %s\n", retryList.front()->getPeer()->name());        retryList.front()->sendRetry();        // If inRetry is still true, sendTiming wasn't called        if (inRetry)        {            retryList.front()->onRetryList(false);            retryList.pop_front();            inRetry = false;            //Bring tickNextIdle up to the present            while (tickNextIdle < curTick)                tickNextIdle += clock;            //Burn a cycle for the missed grant.            tickNextIdle += clock;            busIdle.reschedule(tickNextIdle, true);        }    }    //If we weren't able to drain before, we might be able to now.    if (drainEvent && retryList.size() == 0 && curTick >= tickNextIdle) {        drainEvent->process();        // Clear the drain event once we're done with it.        drainEvent = NULL;    }}intBus::findPort(Addr addr){    /* An interval tree would be a better way to do this. --ali. */    int dest_id = -1;    dest_id = checkPortCache(addr);    if (dest_id == -1) {        PortIter i = portMap.find(RangeSize(addr,1));        if (i != portMap.end()) {            dest_id = i->second;            updatePortCache(dest_id, i->first.start, i->first.end);        }    }    // Check if this matches the default range    if (dest_id == -1) {        AddrRangeIter a_end = defaultRange.end();        for (AddrRangeIter i = defaultRange.begin(); i != a_end; i++) {            if (*i == addr) {                DPRINTF(Bus, "  found addr %#llx on default\n", addr);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -