RubyPort.cc revision 9245:e215ee9db617
1/* 2 * Copyright (c) 2012 ARM Limited 3 * All rights reserved. 4 * 5 * The license below extends only to copyright in the software and shall 6 * not be construed as granting a license to any other intellectual 7 * property including but not limited to intellectual property relating 8 * to a hardware implementation of the functionality of the software 9 * licensed hereunder. You may use the software subject to the license 10 * terms below provided that you ensure that this notice is replicated 11 * unmodified and in its entirety in all distributions of the software, 12 * modified or unmodified, in source code or in binary form. 13 * 14 * Copyright (c) 2009 Advanced Micro Devices, Inc. 15 * Copyright (c) 2011 Mark D. Hill and David A. Wood 16 * All rights reserved. 17 * 18 * Redistribution and use in source and binary forms, with or without 19 * modification, are permitted provided that the following conditions are 20 * met: redistributions of source code must retain the above copyright 21 * notice, this list of conditions and the following disclaimer; 22 * redistributions in binary form must reproduce the above copyright 23 * notice, this list of conditions and the following disclaimer in the 24 * documentation and/or other materials provided with the distribution; 25 * neither the name of the copyright holders nor the names of its 26 * contributors may be used to endorse or promote products derived from 27 * this software without specific prior written permission. 28 * 29 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 30 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 31 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 32 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 33 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 34 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 35 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 36 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 37 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 38 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 39 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 40 */ 41 42#include "cpu/testers/rubytest/RubyTester.hh" 43#include "debug/Config.hh" 44#include "debug/Drain.hh" 45#include "debug/Ruby.hh" 46#include "mem/protocol/AccessPermission.hh" 47#include "mem/ruby/slicc_interface/AbstractController.hh" 48#include "mem/ruby/system/RubyPort.hh" 49#include "sim/system.hh" 50 51RubyPort::RubyPort(const Params *p) 52 : MemObject(p), m_version(p->version), m_controller(NULL), 53 m_mandatory_q_ptr(NULL), 54 pio_port(csprintf("%s-pio-port", name()), this), 55 m_usingRubyTester(p->using_ruby_tester), m_request_cnt(0), 56 drainEvent(NULL), ruby_system(p->ruby_system), system(p->system), 57 waitingOnSequencer(false), access_phys_mem(p->access_phys_mem) 58{ 59 assert(m_version != -1); 60 61 // create the slave ports based on the number of connected ports 62 for (size_t i = 0; i < p->port_slave_connection_count; ++i) { 63 slave_ports.push_back(new M5Port(csprintf("%s-slave%d", name(), i), 64 this, ruby_system, access_phys_mem)); 65 } 66 67 // create the master ports based on the number of connected ports 68 for (size_t i = 0; i < p->port_master_connection_count; ++i) { 69 master_ports.push_back(new PioPort(csprintf("%s-master%d", name(), i), 70 this)); 71 } 72} 73 74void 75RubyPort::init() 76{ 77 assert(m_controller != NULL); 78 m_mandatory_q_ptr = m_controller->getMandatoryQueue(); 79} 80 81MasterPort & 82RubyPort::getMasterPort(const std::string &if_name, int idx) 83{ 84 if (if_name == "pio_port") { 85 return pio_port; 86 } 87 88 // used by the x86 CPUs to connect the interrupt PIO and interrupt slave 89 // port 90 if (if_name != "master") { 91 // pass it along to our super class 92 return MemObject::getMasterPort(if_name, idx); 93 } else { 94 if (idx >= static_cast<int>(master_ports.size())) { 95 panic("RubyPort::getMasterPort: unknown index %d\n", idx); 96 } 97 98 return *master_ports[idx]; 99 } 100} 101 102SlavePort & 103RubyPort::getSlavePort(const std::string &if_name, int idx) 104{ 105 // used by the CPUs to connect the caches to the interconnect, and 106 // for the x86 case also the interrupt master 107 if (if_name != "slave") { 108 // pass it along to our super class 109 return MemObject::getSlavePort(if_name, idx); 110 } else { 111 if (idx >= static_cast<int>(slave_ports.size())) { 112 panic("RubyPort::getSlavePort: unknown index %d\n", idx); 113 } 114 115 return *slave_ports[idx]; 116 } 117} 118 119RubyPort::PioPort::PioPort(const std::string &_name, 120 RubyPort *_port) 121 : QueuedMasterPort(_name, _port, queue), queue(*_port, *this), 122 ruby_port(_port) 123{ 124 DPRINTF(RubyPort, "creating master port on ruby sequencer %s\n", _name); 125} 126 127RubyPort::M5Port::M5Port(const std::string &_name, RubyPort *_port, 128 RubySystem *_system, bool _access_phys_mem) 129 : QueuedSlavePort(_name, _port, queue), queue(*_port, *this), 130 ruby_port(_port), ruby_system(_system), 131 _onRetryList(false), access_phys_mem(_access_phys_mem) 132{ 133 DPRINTF(RubyPort, "creating slave port on ruby sequencer %s\n", _name); 134} 135 136Tick 137RubyPort::M5Port::recvAtomic(PacketPtr pkt) 138{ 139 panic("RubyPort::M5Port::recvAtomic() not implemented!\n"); 140 return 0; 141} 142 143 144bool 145RubyPort::PioPort::recvTimingResp(PacketPtr pkt) 146{ 147 // In FS mode, ruby memory will receive pio responses from devices 148 // and it must forward these responses back to the particular CPU. 149 DPRINTF(RubyPort, "Pio response for address %#x\n", pkt->getAddr()); 150 151 // First we must retrieve the request port from the sender State 152 RubyPort::SenderState *senderState = 153 safe_cast<RubyPort::SenderState *>(pkt->senderState); 154 M5Port *port = senderState->port; 155 assert(port != NULL); 156 157 // pop the sender state from the packet 158 pkt->senderState = senderState->saved; 159 delete senderState; 160 161 port->sendTimingResp(pkt); 162 163 return true; 164} 165 166bool 167RubyPort::M5Port::recvTimingReq(PacketPtr pkt) 168{ 169 DPRINTF(RubyPort, 170 "Timing access caught for address %#x\n", pkt->getAddr()); 171 172 //dsm: based on SimpleTimingPort::recvTimingReq(pkt); 173 174 // The received packets should only be M5 requests, which should never 175 // get nacked. There used to be code to hanldle nacks here, but 176 // I'm pretty sure it didn't work correctly with the drain code, 177 // so that would need to be fixed if we ever added it back. 178 179 if (pkt->memInhibitAsserted()) { 180 warn("memInhibitAsserted???"); 181 // snooper will supply based on copy of packet 182 // still target's responsibility to delete packet 183 delete pkt; 184 return true; 185 } 186 187 // Save the port in the sender state object to be used later to 188 // route the response 189 pkt->senderState = new SenderState(this, pkt->senderState); 190 191 // Check for pio requests and directly send them to the dedicated 192 // pio port. 193 if (!isPhysMemAddress(pkt->getAddr())) { 194 assert(ruby_port->pio_port.isConnected()); 195 DPRINTF(RubyPort, 196 "Request for address 0x%#x is assumed to be a pio request\n", 197 pkt->getAddr()); 198 199 // send next cycle 200 ruby_port->pio_port.schedTimingReq(pkt, 201 curTick() + g_system_ptr->clockPeriod()); 202 return true; 203 } 204 205 assert(Address(pkt->getAddr()).getOffset() + pkt->getSize() <= 206 RubySystem::getBlockSizeBytes()); 207 208 // Submit the ruby request 209 RequestStatus requestStatus = ruby_port->makeRequest(pkt); 210 211 // If the request successfully issued then we should return true. 212 // Otherwise, we need to delete the senderStatus we just created and return 213 // false. 214 if (requestStatus == RequestStatus_Issued) { 215 DPRINTF(RubyPort, "Request %#x issued\n", pkt->getAddr()); 216 return true; 217 } 218 219 // 220 // Unless one is using the ruby tester, record the stalled M5 port for 221 // later retry when the sequencer becomes free. 222 // 223 if (!ruby_port->m_usingRubyTester) { 224 ruby_port->addToRetryList(this); 225 } 226 227 DPRINTF(RubyPort, 228 "Request for address %#x did not issue because %s\n", 229 pkt->getAddr(), RequestStatus_to_string(requestStatus)); 230 231 SenderState* senderState = safe_cast<SenderState*>(pkt->senderState); 232 pkt->senderState = senderState->saved; 233 delete senderState; 234 return false; 235} 236 237bool 238RubyPort::M5Port::doFunctionalRead(PacketPtr pkt) 239{ 240 Address address(pkt->getAddr()); 241 Address line_address(address); 242 line_address.makeLineAddress(); 243 244 AccessPermission access_perm = AccessPermission_NotPresent; 245 int num_controllers = ruby_system->m_abs_cntrl_vec.size(); 246 247 DPRINTF(RubyPort, "Functional Read request for %s\n",address); 248 249 unsigned int num_ro = 0; 250 unsigned int num_rw = 0; 251 unsigned int num_busy = 0; 252 unsigned int num_backing_store = 0; 253 unsigned int num_invalid = 0; 254 255 // In this loop we count the number of controllers that have the given 256 // address in read only, read write and busy states. 257 for (int i = 0; i < num_controllers; ++i) { 258 access_perm = ruby_system->m_abs_cntrl_vec[i]-> 259 getAccessPermission(line_address); 260 if (access_perm == AccessPermission_Read_Only) 261 num_ro++; 262 else if (access_perm == AccessPermission_Read_Write) 263 num_rw++; 264 else if (access_perm == AccessPermission_Busy) 265 num_busy++; 266 else if (access_perm == AccessPermission_Backing_Store) 267 // See RubySlicc_Exports.sm for details, but Backing_Store is meant 268 // to represent blocks in memory *for Broadcast/Snooping protocols*, 269 // where memory has no idea whether it has an exclusive copy of data 270 // or not. 271 num_backing_store++; 272 else if (access_perm == AccessPermission_Invalid || 273 access_perm == AccessPermission_NotPresent) 274 num_invalid++; 275 } 276 assert(num_rw <= 1); 277 278 uint8_t *data = pkt->getPtr<uint8_t>(true); 279 unsigned int size_in_bytes = pkt->getSize(); 280 unsigned startByte = address.getAddress() - line_address.getAddress(); 281 282 // This if case is meant to capture what happens in a Broadcast/Snoop 283 // protocol where the block does not exist in the cache hierarchy. You 284 // only want to read from the Backing_Store memory if there is no copy in 285 // the cache hierarchy, otherwise you want to try to read the RO or RW 286 // copies existing in the cache hierarchy (covered by the else statement). 287 // The reason is because the Backing_Store memory could easily be stale, if 288 // there are copies floating around the cache hierarchy, so you want to read 289 // it only if it's not in the cache hierarchy at all. 290 if (num_invalid == (num_controllers - 1) && 291 num_backing_store == 1) 292 { 293 DPRINTF(RubyPort, "only copy in Backing_Store memory, read from it\n"); 294 for (int i = 0; i < num_controllers; ++i) { 295 access_perm = ruby_system->m_abs_cntrl_vec[i] 296 ->getAccessPermission(line_address); 297 if (access_perm == AccessPermission_Backing_Store) { 298 DataBlock& block = ruby_system->m_abs_cntrl_vec[i] 299 ->getDataBlock(line_address); 300 301 DPRINTF(RubyPort, "reading from %s block %s\n", 302 ruby_system->m_abs_cntrl_vec[i]->name(), block); 303 for (unsigned i = 0; i < size_in_bytes; ++i) { 304 data[i] = block.getByte(i + startByte); 305 } 306 return true; 307 } 308 } 309 } else { 310 // In Broadcast/Snoop protocols, this covers if you know the block 311 // exists somewhere in the caching hierarchy, then you want to read any 312 // valid RO or RW block. In directory protocols, same thing, you want 313 // to read any valid readable copy of the block. 314 DPRINTF(RubyPort, "num_busy = %d, num_ro = %d, num_rw = %d\n", 315 num_busy, num_ro, num_rw); 316 // In this loop, we try to figure which controller has a read only or 317 // a read write copy of the given address. Any valid copy would suffice 318 // for a functional read. 319 for(int i = 0;i < num_controllers;++i) { 320 access_perm = ruby_system->m_abs_cntrl_vec[i] 321 ->getAccessPermission(line_address); 322 if(access_perm == AccessPermission_Read_Only || 323 access_perm == AccessPermission_Read_Write) 324 { 325 DataBlock& block = ruby_system->m_abs_cntrl_vec[i] 326 ->getDataBlock(line_address); 327 328 DPRINTF(RubyPort, "reading from %s block %s\n", 329 ruby_system->m_abs_cntrl_vec[i]->name(), block); 330 for (unsigned i = 0; i < size_in_bytes; ++i) { 331 data[i] = block.getByte(i + startByte); 332 } 333 return true; 334 } 335 } 336 } 337 return false; 338} 339 340bool 341RubyPort::M5Port::doFunctionalWrite(PacketPtr pkt) 342{ 343 Address addr(pkt->getAddr()); 344 Address line_addr = line_address(addr); 345 AccessPermission access_perm = AccessPermission_NotPresent; 346 int num_controllers = ruby_system->m_abs_cntrl_vec.size(); 347 348 DPRINTF(RubyPort, "Functional Write request for %s\n",addr); 349 350 unsigned int num_ro = 0; 351 unsigned int num_rw = 0; 352 unsigned int num_busy = 0; 353 unsigned int num_backing_store = 0; 354 unsigned int num_invalid = 0; 355 356 // In this loop we count the number of controllers that have the given 357 // address in read only, read write and busy states. 358 for(int i = 0;i < num_controllers;++i) { 359 access_perm = ruby_system->m_abs_cntrl_vec[i]-> 360 getAccessPermission(line_addr); 361 if (access_perm == AccessPermission_Read_Only) 362 num_ro++; 363 else if (access_perm == AccessPermission_Read_Write) 364 num_rw++; 365 else if (access_perm == AccessPermission_Busy) 366 num_busy++; 367 else if (access_perm == AccessPermission_Backing_Store) 368 // See RubySlicc_Exports.sm for details, but Backing_Store is meant 369 // to represent blocks in memory *for Broadcast/Snooping protocols*, 370 // where memory has no idea whether it has an exclusive copy of data 371 // or not. 372 num_backing_store++; 373 else if (access_perm == AccessPermission_Invalid || 374 access_perm == AccessPermission_NotPresent) 375 num_invalid++; 376 } 377 378 // If the number of read write copies is more than 1, then there is bug in 379 // coherence protocol. Otherwise, if all copies are in stable states, i.e. 380 // num_busy == 0, we update all the copies. If there is at least one copy 381 // in busy state, then we check if there is read write copy. If yes, then 382 // also we let the access go through. Or, if there is no copy in the cache 383 // hierarchy at all, we still want to do the write to the memory 384 // (Backing_Store) instead of failing. 385 386 DPRINTF(RubyPort, "num_busy = %d, num_ro = %d, num_rw = %d\n", 387 num_busy, num_ro, num_rw); 388 assert(num_rw <= 1); 389 390 uint8_t *data = pkt->getPtr<uint8_t>(true); 391 unsigned int size_in_bytes = pkt->getSize(); 392 unsigned startByte = addr.getAddress() - line_addr.getAddress(); 393 394 if ((num_busy == 0 && num_ro > 0) || num_rw == 1 || 395 (num_invalid == (num_controllers - 1) && num_backing_store == 1)) 396 { 397 for(int i = 0; i < num_controllers;++i) { 398 access_perm = ruby_system->m_abs_cntrl_vec[i]-> 399 getAccessPermission(line_addr); 400 if(access_perm == AccessPermission_Read_Only || 401 access_perm == AccessPermission_Read_Write|| 402 access_perm == AccessPermission_Maybe_Stale || 403 access_perm == AccessPermission_Backing_Store) 404 { 405 DataBlock& block = ruby_system->m_abs_cntrl_vec[i] 406 ->getDataBlock(line_addr); 407 408 DPRINTF(RubyPort, "%s\n",block); 409 for (unsigned i = 0; i < size_in_bytes; ++i) { 410 block.setByte(i + startByte, data[i]); 411 } 412 DPRINTF(RubyPort, "%s\n",block); 413 } 414 } 415 return true; 416 } 417 return false; 418} 419 420void 421RubyPort::M5Port::recvFunctional(PacketPtr pkt) 422{ 423 DPRINTF(RubyPort, "Functional access caught for address %#x\n", 424 pkt->getAddr()); 425 426 // Check for pio requests and directly send them to the dedicated 427 // pio port. 428 if (!isPhysMemAddress(pkt->getAddr())) { 429 assert(ruby_port->pio_port.isConnected()); 430 DPRINTF(RubyPort, "Request for address 0x%#x is a pio request\n", 431 pkt->getAddr()); 432 panic("RubyPort::PioPort::recvFunctional() not implemented!\n"); 433 } 434 435 assert(pkt->getAddr() + pkt->getSize() <= 436 line_address(Address(pkt->getAddr())).getAddress() + 437 RubySystem::getBlockSizeBytes()); 438 439 bool accessSucceeded = false; 440 bool needsResponse = pkt->needsResponse(); 441 442 // Do the functional access on ruby memory 443 if (pkt->isRead()) { 444 accessSucceeded = doFunctionalRead(pkt); 445 } else if (pkt->isWrite()) { 446 accessSucceeded = doFunctionalWrite(pkt); 447 } else { 448 panic("RubyPort: unsupported functional command %s\n", 449 pkt->cmdString()); 450 } 451 452 // Unless the requester explicitly said otherwise, generate an error if 453 // the functional request failed 454 if (!accessSucceeded && !pkt->suppressFuncError()) { 455 fatal("Ruby functional %s failed for address %#x\n", 456 pkt->isWrite() ? "write" : "read", pkt->getAddr()); 457 } 458 459 if (access_phys_mem) { 460 // The attached physmem contains the official version of data. 461 // The following command performs the real functional access. 462 // This line should be removed once Ruby supplies the official version 463 // of data. 464 ruby_port->system->getPhysMem().functionalAccess(pkt); 465 } 466 467 // turn packet around to go back to requester if response expected 468 if (needsResponse) { 469 pkt->setFunctionalResponseStatus(accessSucceeded); 470 471 // @todo There should not be a reverse call since the response is 472 // communicated through the packet pointer 473 // DPRINTF(RubyPort, "Sending packet back over port\n"); 474 // sendFunctional(pkt); 475 } 476 DPRINTF(RubyPort, "Functional access %s!\n", 477 accessSucceeded ? "successful":"failed"); 478} 479 480void 481RubyPort::ruby_hit_callback(PacketPtr pkt) 482{ 483 // Retrieve the request port from the sender State 484 RubyPort::SenderState *senderState = 485 safe_cast<RubyPort::SenderState *>(pkt->senderState); 486 M5Port *port = senderState->port; 487 assert(port != NULL); 488 489 // pop the sender state from the packet 490 pkt->senderState = senderState->saved; 491 delete senderState; 492 493 port->hitCallback(pkt); 494 495 // 496 // If we had to stall the M5Ports, wake them up because the sequencer 497 // likely has free resources now. 498 // 499 if (waitingOnSequencer) { 500 // 501 // Record the current list of ports to retry on a temporary list before 502 // calling sendRetry on those ports. sendRetry will cause an 503 // immediate retry, which may result in the ports being put back on the 504 // list. Therefore we want to clear the retryList before calling 505 // sendRetry. 506 // 507 std::list<M5Port*> curRetryList(retryList); 508 509 retryList.clear(); 510 waitingOnSequencer = false; 511 512 for (std::list<M5Port*>::iterator i = curRetryList.begin(); 513 i != curRetryList.end(); ++i) { 514 DPRINTF(RubyPort, 515 "Sequencer may now be free. SendRetry to port %s\n", 516 (*i)->name()); 517 (*i)->onRetryList(false); 518 (*i)->sendRetry(); 519 } 520 } 521 522 testDrainComplete(); 523} 524 525void 526RubyPort::testDrainComplete() 527{ 528 //If we weren't able to drain before, we might be able to now. 529 if (drainEvent != NULL) { 530 unsigned int drainCount = outstandingCount(); 531 DPRINTF(Drain, "Drain count: %u\n", drainCount); 532 if (drainCount == 0) { 533 DPRINTF(Drain, "RubyPort done draining, processing drain event\n"); 534 drainEvent->process(); 535 // Clear the drain event once we're done with it. 536 drainEvent = NULL; 537 } 538 } 539} 540 541unsigned int 542RubyPort::getChildDrainCount(Event *de) 543{ 544 int count = 0; 545 546 if (pio_port.isConnected()) { 547 count += pio_port.drain(de); 548 DPRINTF(Config, "count after pio check %d\n", count); 549 } 550 551 for (CpuPortIter p = slave_ports.begin(); p != slave_ports.end(); ++p) { 552 count += (*p)->drain(de); 553 DPRINTF(Config, "count after slave port check %d\n", count); 554 } 555 556 for (std::vector<PioPort*>::iterator p = master_ports.begin(); 557 p != master_ports.end(); ++p) { 558 count += (*p)->drain(de); 559 DPRINTF(Config, "count after master port check %d\n", count); 560 } 561 562 DPRINTF(Config, "final count %d\n", count); 563 564 return count; 565} 566 567unsigned int 568RubyPort::drain(Event *de) 569{ 570 if (isDeadlockEventScheduled()) { 571 descheduleDeadlockEvent(); 572 } 573 574 // 575 // If the RubyPort is not empty, then it needs to clear all outstanding 576 // requests before it should call drainEvent->process() 577 // 578 DPRINTF(Config, "outstanding count %d\n", outstandingCount()); 579 bool need_drain = outstandingCount() > 0; 580 581 // 582 // Also, get the number of child ports that will also need to clear 583 // their buffered requests before they call drainEvent->process() 584 // 585 unsigned int child_drain_count = getChildDrainCount(de); 586 587 // Set status 588 if (need_drain) { 589 drainEvent = de; 590 591 DPRINTF(Drain, "RubyPort not drained\n"); 592 changeState(SimObject::Draining); 593 return child_drain_count + 1; 594 } 595 596 drainEvent = NULL; 597 changeState(SimObject::Drained); 598 return child_drain_count; 599} 600 601void 602RubyPort::M5Port::hitCallback(PacketPtr pkt) 603{ 604 bool needsResponse = pkt->needsResponse(); 605 606 // 607 // Unless specified at configuraiton, all responses except failed SC 608 // and Flush operations access M5 physical memory. 609 // 610 bool accessPhysMem = access_phys_mem; 611 612 if (pkt->isLLSC()) { 613 if (pkt->isWrite()) { 614 if (pkt->req->getExtraData() != 0) { 615 // 616 // Successful SC packets convert to normal writes 617 // 618 pkt->convertScToWrite(); 619 } else { 620 // 621 // Failed SC packets don't access physical memory and thus 622 // the RubyPort itself must convert it to a response. 623 // 624 accessPhysMem = false; 625 } 626 } else { 627 // 628 // All LL packets convert to normal loads so that M5 PhysMem does 629 // not lock the blocks. 630 // 631 pkt->convertLlToRead(); 632 } 633 } 634 635 // 636 // Flush requests don't access physical memory 637 // 638 if (pkt->isFlush()) { 639 accessPhysMem = false; 640 } 641 642 DPRINTF(RubyPort, "Hit callback needs response %d\n", needsResponse); 643 644 if (accessPhysMem) { 645 ruby_port->system->getPhysMem().access(pkt); 646 } else if (needsResponse) { 647 pkt->makeResponse(); 648 } 649 650 // turn packet around to go back to requester if response expected 651 if (needsResponse) { 652 DPRINTF(RubyPort, "Sending packet back over port\n"); 653 // send next cycle 654 schedTimingResp(pkt, curTick() + g_system_ptr->clockPeriod()); 655 } else { 656 delete pkt; 657 } 658 DPRINTF(RubyPort, "Hit callback done!\n"); 659} 660 661AddrRangeList 662RubyPort::M5Port::getAddrRanges() const 663{ 664 // at the moment the assumption is that the master does not care 665 AddrRangeList ranges; 666 return ranges; 667} 668 669bool 670RubyPort::M5Port::isPhysMemAddress(Addr addr) 671{ 672 return ruby_port->system->isMemAddr(addr); 673} 674 675unsigned 676RubyPort::M5Port::deviceBlockSize() const 677{ 678 return (unsigned) RubySystem::getBlockSizeBytes(); 679} 680 681void 682RubyPort::ruby_eviction_callback(const Address& address) 683{ 684 DPRINTF(RubyPort, "Sending invalidations.\n"); 685 // should this really be using funcMasterId? 686 Request req(address.getAddress(), 0, 0, Request::funcMasterId); 687 for (CpuPortIter p = slave_ports.begin(); p != slave_ports.end(); ++p) { 688 // check if the connected master port is snooping 689 if ((*p)->isSnooping()) { 690 Packet *pkt = new Packet(&req, MemCmd::InvalidationReq); 691 // send as a snoop request 692 (*p)->sendTimingSnoopReq(pkt); 693 } 694 } 695} 696