coherent_xbar.cc revision 3244
12568SN/A/* 22568SN/A * Copyright (c) 2006 The Regents of The University of Michigan 37636Ssteve.reinhardt@amd.com * All rights reserved. 42568SN/A * 52568SN/A * Redistribution and use in source and binary forms, with or without 62568SN/A * modification, are permitted provided that the following conditions are 72568SN/A * met: redistributions of source code must retain the above copyright 82568SN/A * notice, this list of conditions and the following disclaimer; 92568SN/A * redistributions in binary form must reproduce the above copyright 102568SN/A * notice, this list of conditions and the following disclaimer in the 112568SN/A * documentation and/or other materials provided with the distribution; 122568SN/A * neither the name of the copyright holders nor the names of its 132568SN/A * contributors may be used to endorse or promote products derived from 142568SN/A * this software without specific prior written permission. 152568SN/A * 162568SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 172568SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 182568SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 192568SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 202568SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 212568SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 222568SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 232568SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 242568SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 252568SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 262568SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 272568SN/A * 282665Ssaidi@eecs.umich.edu * Authors: Ali Saidi 292665Ssaidi@eecs.umich.edu */ 302665Ssaidi@eecs.umich.edu 312568SN/A/** 322568SN/A * @file 332568SN/A * Definition of a bus object. 342568SN/A */ 352568SN/A 362568SN/A 372568SN/A#include "base/misc.hh" 383260Ssaidi@eecs.umich.edu#include "base/trace.hh" 393260Ssaidi@eecs.umich.edu#include "mem/bus.hh" 403918Ssaidi@eecs.umich.edu#include "sim/builder.hh" 415314Sstever@gmail.com 422590SN/APort * 433348Sbinkertn@umich.eduBus::getPort(const std::string &if_name, int idx) 442568SN/A{ 452568SN/A if (if_name == "default") 465735Snate@binkert.org if (defaultPort == NULL) { 475735Snate@binkert.org defaultPort = new BusPort(csprintf("%s-default",name()), this, 484022Sstever@eecs.umich.edu defaultId); 494022Sstever@eecs.umich.edu return defaultPort; 504022Sstever@eecs.umich.edu } else 514022Sstever@eecs.umich.edu fatal("Default port already set\n"); 524022Sstever@eecs.umich.edu 534022Sstever@eecs.umich.edu // if_name ignored? forced to be empty? 544022Sstever@eecs.umich.edu int id = interfaces.size(); 552641Sstever@eecs.umich.edu BusPort *bp = new BusPort(csprintf("%s-p%d", name(), id), this, id); 564022Sstever@eecs.umich.edu interfaces.push_back(bp); 574022Sstever@eecs.umich.edu return bp; 582641Sstever@eecs.umich.edu} 594022Sstever@eecs.umich.edu 604022Sstever@eecs.umich.edu/** Get the ranges of anyone other buses that we are connected to. */ 614022Sstever@eecs.umich.eduvoid 624022Sstever@eecs.umich.eduBus::init() 634473Sstever@eecs.umich.edu{ 644473Sstever@eecs.umich.edu std::vector<BusPort*>::iterator intIter; 655319Sstever@gmail.com 665319Sstever@gmail.com for (intIter = interfaces.begin(); intIter != interfaces.end(); intIter++) 675319Sstever@gmail.com (*intIter)->sendStatusChange(Port::RangeChange); 684022Sstever@eecs.umich.edu} 694626Sstever@eecs.umich.edu 704022Sstever@eecs.umich.eduBus::BusFreeEvent::BusFreeEvent(Bus *_bus) : Event(&mainEventQueue), bus(_bus) 714022Sstever@eecs.umich.edu{} 724626Sstever@eecs.umich.edu 734022Sstever@eecs.umich.eduvoid Bus::BusFreeEvent::process() 744628Sstever@eecs.umich.edu{ 754628Sstever@eecs.umich.edu bus->recvRetry(-1); 764022Sstever@eecs.umich.edu} 774022Sstever@eecs.umich.edu 784022Sstever@eecs.umich.educonst char * Bus::BusFreeEvent::description() 794022Sstever@eecs.umich.edu{ 804022Sstever@eecs.umich.edu return "bus became available"; 814022Sstever@eecs.umich.edu} 824022Sstever@eecs.umich.edu 834022Sstever@eecs.umich.eduvoid Bus::occupyBus(PacketPtr pkt) 844022Sstever@eecs.umich.edu{ 854022Sstever@eecs.umich.edu //Bring tickNextIdle up to the present tick 864022Sstever@eecs.umich.edu //There is some potential ambiguity where a cycle starts, which might make 874022Sstever@eecs.umich.edu //a difference when devices are acting right around a cycle boundary. Using 884022Sstever@eecs.umich.edu //a < allows things which happen exactly on a cycle boundary to take up only 894626Sstever@eecs.umich.edu //the following cycle. Anthing that happens later will have to "wait" for 904626Sstever@eecs.umich.edu //the end of that cycle, and then start using the bus after that. 914022Sstever@eecs.umich.edu while (tickNextIdle < curTick) 924022Sstever@eecs.umich.edu tickNextIdle += clock; 935319Sstever@gmail.com 944022Sstever@eecs.umich.edu // The packet will be sent. Figure out how long it occupies the bus, and 954022Sstever@eecs.umich.edu // how much of that time is for the first "word", aka bus width. 967465Ssteve.reinhardt@amd.com int numCycles = 0; 974628Sstever@eecs.umich.edu // Requests need one cycle to send an address 987465Ssteve.reinhardt@amd.com if (pkt->isRequest()) 997465Ssteve.reinhardt@amd.com numCycles++; 1007465Ssteve.reinhardt@amd.com else if (pkt->isResponse() || pkt->hasData()) { 1017465Ssteve.reinhardt@amd.com // If a packet has data, it needs ceil(size/width) cycles to send it 1024628Sstever@eecs.umich.edu // We're using the "adding instead of dividing" trick again here 1037465Ssteve.reinhardt@amd.com if (pkt->hasData()) { 1047465Ssteve.reinhardt@amd.com int dataSize = pkt->getSize(); 1057465Ssteve.reinhardt@amd.com for (int transmitted = 0; transmitted < dataSize; 1067465Ssteve.reinhardt@amd.com transmitted += width) { 1077465Ssteve.reinhardt@amd.com numCycles++; 1087465Ssteve.reinhardt@amd.com } 1097465Ssteve.reinhardt@amd.com } else { 1105319Sstever@gmail.com // If the packet didn't have data, it must have been a response. 1117465Ssteve.reinhardt@amd.com // Those use the bus for one cycle to send their data. 1124022Sstever@eecs.umich.edu numCycles++; 1134626Sstever@eecs.umich.edu } 1144022Sstever@eecs.umich.edu } 1154022Sstever@eecs.umich.edu 1165319Sstever@gmail.com // The first word will be delivered after the current tick, the delivery 1174040Ssaidi@eecs.umich.edu // of the address if any, and one bus cycle to deliver the data 1185507Sstever@gmail.com pkt->firstWordTime = 1195507Sstever@gmail.com tickNextIdle + 1206076Sgblack@eecs.umich.edu pkt->isRequest() ? clock : 0 + 1215507Sstever@gmail.com clock; 1224626Sstever@eecs.umich.edu 1236076Sgblack@eecs.umich.edu //Advance it numCycles bus cycles. 1244626Sstever@eecs.umich.edu //XXX Should this use the repeated addition trick as well? 1254626Sstever@eecs.umich.edu tickNextIdle += (numCycles * clock); 1267669Ssteve.reinhardt@amd.com if (!busIdle.scheduled()) { 1277669Ssteve.reinhardt@amd.com busIdle.schedule(tickNextIdle); 1287669Ssteve.reinhardt@amd.com } else { 1297669Ssteve.reinhardt@amd.com busIdle.reschedule(tickNextIdle); 1304626Sstever@eecs.umich.edu } 1316076Sgblack@eecs.umich.edu DPRINTF(Bus, "The bus is now occupied from tick %d to %d\n", 1324626Sstever@eecs.umich.edu curTick, tickNextIdle); 1334040Ssaidi@eecs.umich.edu 1344626Sstever@eecs.umich.edu // The bus will become idle once the current packet is delivered. 1354040Ssaidi@eecs.umich.edu pkt->finishTime = tickNextIdle; 1364040Ssaidi@eecs.umich.edu} 1374626Sstever@eecs.umich.edu 1384870Sstever@eecs.umich.edu/** Function called by the port when the bus is receiving a Timing 1395650Sgblack@eecs.umich.edu * transaction.*/ 1405650Sgblack@eecs.umich.edubool 1416063Sgblack@eecs.umich.eduBus::recvTiming(Packet *pkt) 1425650Sgblack@eecs.umich.edu{ 1436063Sgblack@eecs.umich.edu Port *port; 1444870Sstever@eecs.umich.edu DPRINTF(Bus, "recvTiming: packet src %d dest %d addr 0x%x cmd %s\n", 1454986Ssaidi@eecs.umich.edu pkt->getSrc(), pkt->getDest(), pkt->getAddr(), pkt->cmdString()); 1464870Sstever@eecs.umich.edu 1474986Ssaidi@eecs.umich.edu BusPort *pktPort = interfaces[pkt->getSrc()]; 1484870Sstever@eecs.umich.edu 1495314Sstever@gmail.com // If the bus is busy, or other devices are in line ahead of the current 1505314Sstever@gmail.com // one, put this device on the retry list. 1515314Sstever@gmail.com if (tickNextIdle > curTick || 1524022Sstever@eecs.umich.edu (retryList.size() && (!inRetry || pktPort != retryList.front()))) { 1532592SN/A addToRetryList(pktPort); 1543607Srdreslin@umich.edu return false; 1555314Sstever@gmail.com } 1562641Sstever@eecs.umich.edu 1574626Sstever@eecs.umich.edu short dest = pkt->getDest(); 1584626Sstever@eecs.umich.edu if (dest == Packet::Broadcast) { 1594626Sstever@eecs.umich.edu if (timingSnoop(pkt)) { 1604626Sstever@eecs.umich.edu pkt->flags |= SNOOP_COMMIT; 1613260Ssaidi@eecs.umich.edu bool success = timingSnoop(pkt); 1624626Sstever@eecs.umich.edu assert(success); 1634626Sstever@eecs.umich.edu if (pkt->flags & SATISFIED) { 1644626Sstever@eecs.umich.edu //Cache-Cache transfer occuring 1654626Sstever@eecs.umich.edu if (inRetry) { 1663260Ssaidi@eecs.umich.edu retryList.front()->onRetryList(false); 1675314Sstever@gmail.com retryList.pop_front(); 1685314Sstever@gmail.com inRetry = false; 1695314Sstever@gmail.com } 1705314Sstever@gmail.com occupyBus(pkt); 1715314Sstever@gmail.com return true; 1725314Sstever@gmail.com } 1735314Sstever@gmail.com port = findPort(pkt->getAddr(), pkt->getSrc()); 1745314Sstever@gmail.com } else { 1755314Sstever@gmail.com //Snoop didn't succeed 1765314Sstever@gmail.com addToRetryList(pktPort); 1775314Sstever@gmail.com return false; 1784626Sstever@eecs.umich.edu } 1794626Sstever@eecs.umich.edu } else { 1804626Sstever@eecs.umich.edu assert(dest >= 0 && dest < interfaces.size()); 1813260Ssaidi@eecs.umich.edu assert(dest != pkt->getSrc()); // catch infinite loops 1824626Sstever@eecs.umich.edu port = interfaces[dest]; 1834626Sstever@eecs.umich.edu } 1844626Sstever@eecs.umich.edu 1855735Snate@binkert.org occupyBus(pkt); 1864626Sstever@eecs.umich.edu 1873260Ssaidi@eecs.umich.edu if (port->sendTiming(pkt)) { 1884489Sstever@eecs.umich.edu // Packet was successfully sent. Return true. 1894489Sstever@eecs.umich.edu // Also take care of retries 1904489Sstever@eecs.umich.edu if (inRetry) { 1914489Sstever@eecs.umich.edu retryList.front()->onRetryList(false); 1924489Sstever@eecs.umich.edu retryList.pop_front(); 1934489Sstever@eecs.umich.edu inRetry = false; 1944626Sstever@eecs.umich.edu } 1954626Sstever@eecs.umich.edu return true; 1963260Ssaidi@eecs.umich.edu } 1974626Sstever@eecs.umich.edu 1984626Sstever@eecs.umich.edu // Packet not successfully sent. Leave or put it on the retry list. 1995735Snate@binkert.org addToRetryList(pktPort); 2005735Snate@binkert.org return false; 2015735Snate@binkert.org} 2025735Snate@binkert.org 2035735Snate@binkert.orgvoid 2045735Snate@binkert.orgBus::recvRetry(int id) 2053260Ssaidi@eecs.umich.edu{ 2065314Sstever@gmail.com // If there's anything waiting... 2074626Sstever@eecs.umich.edu if (retryList.size()) { 2085314Sstever@gmail.com //retryingPort = retryList.front(); 2095314Sstever@gmail.com inRetry = true; 2105314Sstever@gmail.com retryList.front()->sendRetry(); 2115314Sstever@gmail.com // If inRetry is still true, sendTiming wasn't called 2122641Sstever@eecs.umich.edu if (inRetry) 2133260Ssaidi@eecs.umich.edu panic("Port %s didn't call sendTiming in it's recvRetry\n",\ 2145314Sstever@gmail.com retryList.front()->getPeer()->name()); 2155735Snate@binkert.org //assert(!inRetry); 2163260Ssaidi@eecs.umich.edu } 2175314Sstever@gmail.com} 2185314Sstever@gmail.com 2193260Ssaidi@eecs.umich.eduPort * 2203260Ssaidi@eecs.umich.eduBus::findPort(Addr addr, int id) 2215735Snate@binkert.org{ 2225735Snate@binkert.org /* An interval tree would be a better way to do this. --ali. */ 2235314Sstever@gmail.com int dest_id = -1; 2245314Sstever@gmail.com int i = 0; 2255314Sstever@gmail.com bool found = false; 2265314Sstever@gmail.com AddrRangeIter iter; 2275314Sstever@gmail.com 2285314Sstever@gmail.com while (i < portList.size() && !found) 2295314Sstever@gmail.com { 2305314Sstever@gmail.com if (portList[i].range == addr) { 2315314Sstever@gmail.com dest_id = portList[i].portId; 2325314Sstever@gmail.com found = true; 2335314Sstever@gmail.com DPRINTF(Bus, " found addr %#llx on device %d\n", addr, dest_id); 2345314Sstever@gmail.com } 2355735Snate@binkert.org i++; 2365314Sstever@gmail.com } 2375314Sstever@gmail.com 2385314Sstever@gmail.com // Check if this matches the default range 2395314Sstever@gmail.com if (dest_id == -1) { 2405314Sstever@gmail.com for (iter = defaultRange.begin(); iter != defaultRange.end(); iter++) { 2415735Snate@binkert.org if (*iter == addr) { 2425314Sstever@gmail.com DPRINTF(Bus, " found addr %#llx on default\n", addr); 2435314Sstever@gmail.com return defaultPort; 2445735Snate@binkert.org } 2455314Sstever@gmail.com } 2465314Sstever@gmail.com panic("Unable to find destination for addr: %#llx", addr); 2475314Sstever@gmail.com } 2485314Sstever@gmail.com 2495314Sstever@gmail.com 2505314Sstever@gmail.com // we shouldn't be sending this back to where it came from 2515314Sstever@gmail.com assert(dest_id != id); 2525314Sstever@gmail.com 2535314Sstever@gmail.com return interfaces[dest_id]; 2545314Sstever@gmail.com} 2555314Sstever@gmail.com 2565314Sstever@gmail.comstd::vector<int> 2575314Sstever@gmail.comBus::findSnoopPorts(Addr addr, int id) 2585314Sstever@gmail.com{ 2595314Sstever@gmail.com int i = 0; 2605314Sstever@gmail.com AddrRangeIter iter; 2615314Sstever@gmail.com std::vector<int> ports; 2625314Sstever@gmail.com 2635314Sstever@gmail.com while (i < portSnoopList.size()) 2645314Sstever@gmail.com { 2655314Sstever@gmail.com if (portSnoopList[i].range == addr && portSnoopList[i].portId != id) { 2665314Sstever@gmail.com //Careful to not overlap ranges 2675314Sstever@gmail.com //or snoop will be called more than once on the port 2685314Sstever@gmail.com ports.push_back(portSnoopList[i].portId); 2695314Sstever@gmail.com DPRINTF(Bus, " found snoop addr %#llx on device%d\n", addr, 2705314Sstever@gmail.com portSnoopList[i].portId); 2715314Sstever@gmail.com } 2725314Sstever@gmail.com i++; 2735314Sstever@gmail.com } 2745314Sstever@gmail.com return ports; 2755314Sstever@gmail.com} 2765314Sstever@gmail.com 2775314Sstever@gmail.comvoid 2785314Sstever@gmail.comBus::atomicSnoop(Packet *pkt) 2795314Sstever@gmail.com{ 280 std::vector<int> ports = findSnoopPorts(pkt->getAddr(), pkt->getSrc()); 281 282 while (!ports.empty()) 283 { 284 interfaces[ports.back()]->sendAtomic(pkt); 285 ports.pop_back(); 286 } 287} 288 289void 290Bus::functionalSnoop(Packet *pkt) 291{ 292 std::vector<int> ports = findSnoopPorts(pkt->getAddr(), pkt->getSrc()); 293 294 while (!ports.empty()) 295 { 296 interfaces[ports.back()]->sendFunctional(pkt); 297 ports.pop_back(); 298 } 299} 300 301bool 302Bus::timingSnoop(Packet *pkt) 303{ 304 std::vector<int> ports = findSnoopPorts(pkt->getAddr(), pkt->getSrc()); 305 bool success = true; 306 307 while (!ports.empty() && success) 308 { 309 success = interfaces[ports.back()]->sendTiming(pkt); 310 ports.pop_back(); 311 } 312 313 return success; 314} 315 316 317/** Function called by the port when the bus is receiving a Atomic 318 * transaction.*/ 319Tick 320Bus::recvAtomic(Packet *pkt) 321{ 322 DPRINTF(Bus, "recvAtomic: packet src %d dest %d addr 0x%x cmd %s\n", 323 pkt->getSrc(), pkt->getDest(), pkt->getAddr(), pkt->cmdString()); 324 assert(pkt->getDest() == Packet::Broadcast); 325 atomicSnoop(pkt); 326 return findPort(pkt->getAddr(), pkt->getSrc())->sendAtomic(pkt); 327} 328 329/** Function called by the port when the bus is receiving a Functional 330 * transaction.*/ 331void 332Bus::recvFunctional(Packet *pkt) 333{ 334 DPRINTF(Bus, "recvFunctional: packet src %d dest %d addr 0x%x cmd %s\n", 335 pkt->getSrc(), pkt->getDest(), pkt->getAddr(), pkt->cmdString()); 336 assert(pkt->getDest() == Packet::Broadcast); 337 functionalSnoop(pkt); 338 findPort(pkt->getAddr(), pkt->getSrc())->sendFunctional(pkt); 339} 340 341/** Function called by the port when the bus is receiving a status change.*/ 342void 343Bus::recvStatusChange(Port::Status status, int id) 344{ 345 AddrRangeList ranges; 346 AddrRangeList snoops; 347 int x; 348 AddrRangeIter iter; 349 350 assert(status == Port::RangeChange && 351 "The other statuses need to be implemented."); 352 353 DPRINTF(BusAddrRanges, "received RangeChange from device id %d\n", id); 354 355 if (id == defaultId) { 356 defaultRange.clear(); 357 defaultPort->getPeerAddressRanges(ranges, snoops); 358 assert(snoops.size() == 0); 359 for(iter = ranges.begin(); iter != ranges.end(); iter++) { 360 defaultRange.push_back(*iter); 361 DPRINTF(BusAddrRanges, "Adding range %#llx - %#llx for default range\n", 362 iter->start, iter->end); 363 } 364 } else { 365 366 assert((id < interfaces.size() && id >= 0) || id == -1); 367 Port *port = interfaces[id]; 368 std::vector<DevMap>::iterator portIter; 369 std::vector<DevMap>::iterator snoopIter; 370 371 // Clean out any previously existent ids 372 for (portIter = portList.begin(); portIter != portList.end(); ) { 373 if (portIter->portId == id) 374 portIter = portList.erase(portIter); 375 else 376 portIter++; 377 } 378 379 for (snoopIter = portSnoopList.begin(); snoopIter != portSnoopList.end(); ) { 380 if (snoopIter->portId == id) 381 snoopIter = portSnoopList.erase(snoopIter); 382 else 383 snoopIter++; 384 } 385 386 port->getPeerAddressRanges(ranges, snoops); 387 388 for(iter = snoops.begin(); iter != snoops.end(); iter++) { 389 DevMap dm; 390 dm.portId = id; 391 dm.range = *iter; 392 393 DPRINTF(BusAddrRanges, "Adding snoop range %#llx - %#llx for id %d\n", 394 dm.range.start, dm.range.end, id); 395 portSnoopList.push_back(dm); 396 } 397 398 for(iter = ranges.begin(); iter != ranges.end(); iter++) { 399 DevMap dm; 400 dm.portId = id; 401 dm.range = *iter; 402 403 DPRINTF(BusAddrRanges, "Adding range %#llx - %#llx for id %d\n", 404 dm.range.start, dm.range.end, id); 405 portList.push_back(dm); 406 } 407 } 408 DPRINTF(MMU, "port list has %d entries\n", portList.size()); 409 410 // tell all our peers that our address range has changed. 411 // Don't tell the device that caused this change, it already knows 412 for (x = 0; x < interfaces.size(); x++) 413 if (x != id) 414 interfaces[x]->sendStatusChange(Port::RangeChange); 415 416 if (id != defaultId && defaultPort) 417 defaultPort->sendStatusChange(Port::RangeChange); 418} 419 420void 421Bus::addressRanges(AddrRangeList &resp, AddrRangeList &snoop, int id) 422{ 423 std::vector<DevMap>::iterator portIter; 424 AddrRangeIter dflt_iter; 425 bool subset; 426 427 resp.clear(); 428 snoop.clear(); 429 430 DPRINTF(BusAddrRanges, "received address range request, returning:\n"); 431 432 for (dflt_iter = defaultRange.begin(); dflt_iter != defaultRange.end(); 433 dflt_iter++) { 434 resp.push_back(*dflt_iter); 435 DPRINTF(BusAddrRanges, " -- %#llx : %#llx\n",dflt_iter->start, 436 dflt_iter->end); 437 } 438 for (portIter = portList.begin(); portIter != portList.end(); portIter++) { 439 subset = false; 440 for (dflt_iter = defaultRange.begin(); dflt_iter != defaultRange.end(); 441 dflt_iter++) { 442 if ((portIter->range.start < dflt_iter->start && 443 portIter->range.end >= dflt_iter->start) || 444 (portIter->range.start < dflt_iter->end && 445 portIter->range.end >= dflt_iter->end)) 446 fatal("Devices can not set ranges that itersect the default set\ 447 but are not a subset of the default set.\n"); 448 if (portIter->range.start >= dflt_iter->start && 449 portIter->range.end <= dflt_iter->end) { 450 subset = true; 451 DPRINTF(BusAddrRanges, " -- %#llx : %#llx is a SUBSET\n", 452 portIter->range.start, portIter->range.end); 453 } 454 } 455 if (portIter->portId != id && !subset) { 456 resp.push_back(portIter->range); 457 DPRINTF(BusAddrRanges, " -- %#llx : %#llx\n", 458 portIter->range.start, portIter->range.end); 459 } 460 } 461} 462 463BEGIN_DECLARE_SIM_OBJECT_PARAMS(Bus) 464 465 Param<int> bus_id; 466 Param<int> clock; 467 Param<int> width; 468 469END_DECLARE_SIM_OBJECT_PARAMS(Bus) 470 471BEGIN_INIT_SIM_OBJECT_PARAMS(Bus) 472 INIT_PARAM(bus_id, "a globally unique bus id"), 473 INIT_PARAM(clock, "bus clock speed"), 474 INIT_PARAM(width, "width of the bus (bits)") 475END_INIT_SIM_OBJECT_PARAMS(Bus) 476 477CREATE_SIM_OBJECT(Bus) 478{ 479 return new Bus(getInstanceName(), bus_id, clock, width); 480} 481 482REGISTER_SIM_OBJECT("Bus", Bus) 483