📄 bus.cc
字号:
/* * 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 + -