RubyPort.cc revision 7035:b78b3a9e205f
1 2/* 3 * Copyright (c) 2009 Advanced Micro Devices, Inc. 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions are 8 * met: redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer; 10 * redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution; 13 * neither the name of the copyright holders nor the names of its 14 * contributors may be used to endorse or promote products derived from 15 * this software without specific prior written permission. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 18 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 20 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 21 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 22 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 23 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 */ 29 30#include "mem/physical.hh" 31#include "mem/ruby/system/RubyPort.hh" 32#include "mem/ruby/slicc_interface/AbstractController.hh" 33#include "cpu/rubytest/RubyTester.hh" 34 35RubyPort::RubyPort(const Params *p) 36 : MemObject(p) 37{ 38 m_version = p->version; 39 assert(m_version != -1); 40 41 physmem = p->physmem; 42 43 m_controller = NULL; 44 m_mandatory_q_ptr = NULL; 45 46 m_request_cnt = 0; 47 pio_port = NULL; 48 physMemPort = NULL; 49} 50 51void RubyPort::init() 52{ 53 assert(m_controller != NULL); 54 m_mandatory_q_ptr = m_controller->getMandatoryQueue(); 55} 56 57Port * 58RubyPort::getPort(const std::string &if_name, int idx) 59{ 60 if (if_name == "port") { 61 return new M5Port(csprintf("%s-port%d", name(), idx), this); 62 } else if (if_name == "pio_port") { 63 // 64 // ensure there is only one pio port 65 // 66 assert(pio_port == NULL); 67 68 pio_port = new PioPort(csprintf("%s-pio-port%d", name(), idx), 69 this); 70 71 return pio_port; 72 } else if (if_name == "physMemPort") { 73 // 74 // RubyPort should only have one port to physical memory 75 // 76 assert (physMemPort == NULL); 77 78 physMemPort = new M5Port(csprintf("%s-physMemPort", name()), 79 this); 80 81 return physMemPort; 82 } else if (if_name == "functional") { 83 // 84 // Calls for the functional port only want to access functional memory. 85 // Therefore, directly pass these calls ports to physmem. 86 // 87 assert(physmem != NULL); 88 return physmem->getPort(if_name, idx); 89 } 90 return NULL; 91} 92 93RubyPort::PioPort::PioPort(const std::string &_name, 94 RubyPort *_port) 95 : SimpleTimingPort(_name, _port) 96{ 97 DPRINTF(Ruby, "creating port to ruby sequencer to cpu %s\n", _name); 98 ruby_port = _port; 99} 100 101RubyPort::M5Port::M5Port(const std::string &_name, 102 RubyPort *_port) 103 : SimpleTimingPort(_name, _port) 104{ 105 DPRINTF(Ruby, "creating port from ruby sequcner to cpu %s\n", _name); 106 ruby_port = _port; 107} 108 109Tick 110RubyPort::PioPort::recvAtomic(PacketPtr pkt) 111{ 112 panic("RubyPort::PioPort::recvAtomic() not implemented!\n"); 113 return 0; 114} 115 116 117Tick 118RubyPort::M5Port::recvAtomic(PacketPtr pkt) 119{ 120 panic("RubyPort::M5Port::recvAtomic() not implemented!\n"); 121 return 0; 122} 123 124 125bool 126RubyPort::PioPort::recvTiming(PacketPtr pkt) 127{ 128 // 129 // In FS mode, ruby memory will receive pio responses from devices and 130 // it must forward these responses back to the particular CPU. 131 // 132 DPRINTF(MemoryAccess, 133 "Pio response for address %#x\n", 134 pkt->getAddr()); 135 136 assert(pkt->isResponse()); 137 138 // 139 // First we must retrieve the request port from the sender State 140 // 141 RubyPort::SenderState *senderState = 142 safe_cast<RubyPort::SenderState *>(pkt->senderState); 143 M5Port *port = senderState->port; 144 assert(port != NULL); 145 146 // pop the sender state from the packet 147 pkt->senderState = senderState->saved; 148 delete senderState; 149 150 port->sendTiming(pkt); 151 152 return true; 153} 154 155bool 156RubyPort::M5Port::recvTiming(PacketPtr pkt) 157{ 158 DPRINTF(MemoryAccess, 159 "Timing access caught for address %#x\n", 160 pkt->getAddr()); 161 162 //dsm: based on SimpleTimingPort::recvTiming(pkt); 163 164 // 165 // The received packets should only be M5 requests, which should never 166 // get nacked. There used to be code to hanldle nacks here, but 167 // I'm pretty sure it didn't work correctly with the drain code, 168 // so that would need to be fixed if we ever added it back. 169 // 170 assert(pkt->isRequest()); 171 172 if (pkt->memInhibitAsserted()) { 173 warn("memInhibitAsserted???"); 174 // snooper will supply based on copy of packet 175 // still target's responsibility to delete packet 176 delete pkt; 177 return true; 178 } 179 180 // 181 // Save the port in the sender state object to be used later to 182 // route the response 183 // 184 pkt->senderState = new SenderState(this, pkt->senderState); 185 186 // 187 // Check for pio requests and directly send them to the dedicated 188 // pio port. 189 // 190 if (!isPhysMemAddress(pkt->getAddr())) { 191 assert(ruby_port->pio_port != NULL); 192 DPRINTF(MemoryAccess, 193 "Request for address 0x%#x is assumed to be a pio request\n", 194 pkt->getAddr()); 195 196 return ruby_port->pio_port->sendTiming(pkt); 197 } 198 199 // 200 // For DMA and CPU requests, translate them to ruby requests before 201 // sending them to our assigned ruby port. 202 // 203 RubyRequestType type = RubyRequestType_NULL; 204 205 // 206 // If valid, copy the pc to the ruby request 207 // 208 Addr pc = 0; 209 if (pkt->req->hasPC()) { 210 pc = pkt->req->getPC(); 211 } 212 213 if (pkt->isLLSC()) { 214 if (pkt->isWrite()) { 215 DPRINTF(MemoryAccess, "Issuing SC\n"); 216 type = RubyRequestType_Locked_Write; 217 } else { 218 DPRINTF(MemoryAccess, "Issuing LL\n"); 219 assert(pkt->isRead()); 220 type = RubyRequestType_Locked_Read; 221 } 222 } else { 223 if (pkt->isRead()) { 224 if (pkt->req->isInstFetch()) { 225 type = RubyRequestType_IFETCH; 226 } else { 227 type = RubyRequestType_LD; 228 } 229 } else if (pkt->isWrite()) { 230 type = RubyRequestType_ST; 231 } else if (pkt->isReadWrite()) { 232 // 233 // Fix me. This conditional will never be executed because 234 // isReadWrite() is just an OR of isRead() and isWrite(). 235 // Furthermore, just because the packet is a read/write request does 236 // not necessary mean it is a read-modify-write atomic operation. 237 // 238 type = RubyRequestType_RMW_Write; 239 } else { 240 panic("Unsupported ruby packet type\n"); 241 } 242 } 243 244 RubyRequest ruby_request(pkt->getAddr(), 245 pkt->getPtr<uint8_t>(), 246 pkt->getSize(), 247 pc, 248 type, 249 RubyAccessMode_Supervisor, 250 pkt); 251 252 // Submit the ruby request 253 RequestStatus requestStatus = ruby_port->makeRequest(ruby_request); 254 255 // 256 // If the request successfully issued or the SC request completed because 257 // exclusive permission was lost, then we should return true. 258 // Otherwise, we need to delete the senderStatus we just created and return 259 // false. 260 // 261 if ((requestStatus == RequestStatus_Issued) || 262 (requestStatus == RequestStatus_LlscFailed)) { 263 264 // 265 // The communicate to M5 whether the SC command succeeded by seting the 266 // packet's extra data. 267 // 268 if (pkt->isLLSC() && pkt->isWrite()) { 269 if (requestStatus == RequestStatus_LlscFailed) { 270 DPRINTF(MemoryAccess, "SC failed and request completed\n"); 271 pkt->req->setExtraData(0); 272 } else { 273 pkt->req->setExtraData(1); 274 } 275 } 276 return true; 277 } 278 279 DPRINTF(MemoryAccess, 280 "Request for address #x did not issue because %s\n", 281 pkt->getAddr(), 282 RequestStatus_to_string(requestStatus)); 283 284 SenderState* senderState = safe_cast<SenderState*>(pkt->senderState); 285 pkt->senderState = senderState->saved; 286 delete senderState; 287 return false; 288} 289 290void 291RubyPort::ruby_hit_callback(PacketPtr pkt) 292{ 293 // 294 // Retrieve the request port from the sender State 295 // 296 RubyPort::SenderState *senderState = 297 safe_cast<RubyPort::SenderState *>(pkt->senderState); 298 M5Port *port = senderState->port; 299 assert(port != NULL); 300 301 // pop the sender state from the packet 302 pkt->senderState = senderState->saved; 303 delete senderState; 304 305 port->hitCallback(pkt); 306} 307 308void 309RubyPort::M5Port::hitCallback(PacketPtr pkt) 310{ 311 312 bool needsResponse = pkt->needsResponse(); 313 314 DPRINTF(MemoryAccess, "Hit callback needs response %d\n", 315 needsResponse); 316 317 ruby_port->physMemPort->sendAtomic(pkt); 318 319 // turn packet around to go back to requester if response expected 320 if (needsResponse) { 321 // sendAtomic() should already have turned packet into 322 // atomic response 323 assert(pkt->isResponse()); 324 DPRINTF(MemoryAccess, "Sending packet back over port\n"); 325 sendTiming(pkt); 326 } else { 327 delete pkt; 328 } 329 DPRINTF(MemoryAccess, "Hit callback done!\n"); 330} 331 332bool 333RubyPort::M5Port::sendTiming(PacketPtr pkt) 334{ 335 schedSendTiming(pkt, curTick + 1); //minimum latency, must be > 0 336 return true; 337} 338 339bool 340RubyPort::PioPort::sendTiming(PacketPtr pkt) 341{ 342 schedSendTiming(pkt, curTick + 1); //minimum latency, must be > 0 343 return true; 344} 345 346bool 347RubyPort::M5Port::isPhysMemAddress(Addr addr) 348{ 349 AddrRangeList physMemAddrList; 350 bool snoop = false; 351 ruby_port->physMemPort->getPeerAddressRanges(physMemAddrList, snoop); 352 for(AddrRangeIter iter = physMemAddrList.begin(); 353 iter != physMemAddrList.end(); 354 iter++) { 355 if (addr >= iter->start && addr <= iter->end) { 356 DPRINTF(MemoryAccess, "Request found in %#llx - %#llx range\n", 357 iter->start, iter->end); 358 return true; 359 } 360 } 361 return false; 362} 363