RubyPort.cc revision 6922:1620cffaa3b6
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->isRead()) { 214 if (pkt->req->isInstFetch()) { 215 type = RubyRequestType_IFETCH; 216 } else { 217 type = RubyRequestType_LD; 218 } 219 } else if (pkt->isWrite()) { 220 type = RubyRequestType_ST; 221 } else if (pkt->isReadWrite()) { 222 type = RubyRequestType_RMW_Write; 223 } else { 224 panic("Unsupported ruby packet type\n"); 225 } 226 227 RubyRequest ruby_request(pkt->getAddr(), 228 pkt->getPtr<uint8_t>(), 229 pkt->getSize(), 230 pc, 231 type, 232 RubyAccessMode_Supervisor, 233 pkt); 234 235 // Submit the ruby request 236 RequestStatus requestStatus = ruby_port->makeRequest(ruby_request); 237 if (requestStatus == RequestStatus_Issued) { 238 return true; 239 } 240 241 DPRINTF(MemoryAccess, 242 "Request for address #x did not issue because %s\n", 243 pkt->getAddr(), 244 RequestStatus_to_string(requestStatus)); 245 246 SenderState* senderState = safe_cast<SenderState*>(pkt->senderState); 247 pkt->senderState = senderState->saved; 248 delete senderState; 249 return false; 250} 251 252void 253RubyPort::ruby_hit_callback(PacketPtr pkt) 254{ 255 // 256 // Retrieve the request port from the sender State 257 // 258 RubyPort::SenderState *senderState = 259 safe_cast<RubyPort::SenderState *>(pkt->senderState); 260 M5Port *port = senderState->port; 261 assert(port != NULL); 262 263 // pop the sender state from the packet 264 pkt->senderState = senderState->saved; 265 delete senderState; 266 267 port->hitCallback(pkt); 268} 269 270void 271RubyPort::M5Port::hitCallback(PacketPtr pkt) 272{ 273 274 bool needsResponse = pkt->needsResponse(); 275 276 DPRINTF(MemoryAccess, "Hit callback needs response %d\n", 277 needsResponse); 278 279 ruby_port->physMemPort->sendAtomic(pkt); 280 281 // turn packet around to go back to requester if response expected 282 if (needsResponse) { 283 // sendAtomic() should already have turned packet into 284 // atomic response 285 assert(pkt->isResponse()); 286 DPRINTF(MemoryAccess, "Sending packet back over port\n"); 287 sendTiming(pkt); 288 } else { 289 delete pkt; 290 } 291 DPRINTF(MemoryAccess, "Hit callback done!\n"); 292} 293 294bool 295RubyPort::M5Port::sendTiming(PacketPtr pkt) 296{ 297 schedSendTiming(pkt, curTick + 1); //minimum latency, must be > 0 298 return true; 299} 300 301bool 302RubyPort::PioPort::sendTiming(PacketPtr pkt) 303{ 304 schedSendTiming(pkt, curTick + 1); //minimum latency, must be > 0 305 return true; 306} 307 308bool 309RubyPort::M5Port::isPhysMemAddress(Addr addr) 310{ 311 AddrRangeList physMemAddrList; 312 bool snoop = false; 313 ruby_port->physMemPort->getPeerAddressRanges(physMemAddrList, snoop); 314 for(AddrRangeIter iter = physMemAddrList.begin(); 315 iter != physMemAddrList.end(); 316 iter++) { 317 if (addr >= iter->start && addr <= iter->end) { 318 DPRINTF(MemoryAccess, "Request found in %#llx - %#llx range\n", 319 iter->start, iter->end); 320 return true; 321 } 322 } 323 return false; 324} 325