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