RubyPort.cc (7035:b78b3a9e205f) | RubyPort.cc (7039:bc0b6ea676b5) |
---|---|
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; --- 12 unchanged lines hidden (view full) --- 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 | 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; --- 12 unchanged lines hidden (view full) --- 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 |
29#include "cpu/rubytest/RubyTester.hh" |
|
30#include "mem/physical.hh" | 30#include "mem/physical.hh" |
31#include "mem/ruby/system/RubyPort.hh" | |
32#include "mem/ruby/slicc_interface/AbstractController.hh" | 31#include "mem/ruby/slicc_interface/AbstractController.hh" |
33#include "cpu/rubytest/RubyTester.hh" | 32#include "mem/ruby/system/RubyPort.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; | 33 34RubyPort::RubyPort(const Params *p) 35 : MemObject(p) 36{ 37 m_version = p->version; 38 assert(m_version != -1); 39 40 physmem = p->physmem; |
42 | 41 |
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 | 42 m_controller = NULL; 43 m_mandatory_q_ptr = NULL; 44 45 m_request_cnt = 0; 46 pio_port = NULL; 47 physMemPort = NULL; 48} 49 |
51void RubyPort::init() | 50void 51RubyPort::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); | 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 // | 62 } 63 64 if (if_name == "pio_port") { |
64 // ensure there is only one pio port | 65 // ensure there is only one pio port |
65 // | |
66 assert(pio_port == NULL); 67 | 66 assert(pio_port == NULL); 67 |
68 pio_port = new PioPort(csprintf("%s-pio-port%d", name(), idx), 69 this); | 68 pio_port = new PioPort(csprintf("%s-pio-port%d", name(), idx), this); |
70 71 return pio_port; | 69 70 return pio_port; |
72 } else if (if_name == "physMemPort") { 73 // | 71 } 72 73 if (if_name == "physMemPort") { |
74 // RubyPort should only have one port to physical memory | 74 // RubyPort should only have one port to physical memory |
75 // | |
76 assert (physMemPort == NULL); 77 | 75 assert (physMemPort == NULL); 76 |
78 physMemPort = new M5Port(csprintf("%s-physMemPort", name()), 79 this); 80 | 77 physMemPort = new M5Port(csprintf("%s-physMemPort", name()), this); 78 |
81 return physMemPort; | 79 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 // | 80 } 81 82 if (if_name == "functional") { 83 // Calls for the functional port only want to access 84 // functional memory. Therefore, directly pass these calls 85 // ports to physmem. |
87 assert(physmem != NULL); 88 return physmem->getPort(if_name, idx); 89 } | 86 assert(physmem != NULL); 87 return physmem->getPort(if_name, idx); 88 } |
89 |
|
90 return NULL; 91} 92 | 90 return NULL; 91} 92 |
93RubyPort::PioPort::PioPort(const std::string &_name, | 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 | 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, | 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 | 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{ | 116Tick 117RubyPort::M5Port::recvAtomic(PacketPtr pkt) 118{ 119 panic("RubyPort::M5Port::recvAtomic() not implemented!\n"); 120 return 0; 121} 122 123 124bool 125RubyPort::PioPort::recvTiming(PacketPtr pkt) 126{ |
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()); | 127 // In FS mode, ruby memory will receive pio responses from devices 128 // and it must forward these responses back to the particular CPU. 129 DPRINTF(MemoryAccess, "Pio response for address %#x\n", pkt->getAddr()); |
135 136 assert(pkt->isResponse()); 137 | 130 131 assert(pkt->isResponse()); 132 |
138 // | |
139 // First we must retrieve the request port from the sender State | 133 // First we must retrieve the request port from the sender State |
140 // 141 RubyPort::SenderState *senderState = | 134 RubyPort::SenderState *senderState = |
142 safe_cast<RubyPort::SenderState *>(pkt->senderState); 143 M5Port *port = senderState->port; 144 assert(port != NULL); | 135 safe_cast<RubyPort::SenderState *>(pkt->senderState); 136 M5Port *port = senderState->port; 137 assert(port != NULL); |
145 | 138 |
146 // pop the sender state from the packet 147 pkt->senderState = senderState->saved; 148 delete senderState; | 139 // pop the sender state from the packet 140 pkt->senderState = senderState->saved; 141 delete senderState; |
149 | 142 |
150 port->sendTiming(pkt); | 143 port->sendTiming(pkt); |
151 | 144 |
152 return true; 153} 154 155bool 156RubyPort::M5Port::recvTiming(PacketPtr pkt) 157{ | 145 return true; 146} 147 148bool 149RubyPort::M5Port::recvTiming(PacketPtr pkt) 150{ |
158 DPRINTF(MemoryAccess, 159 "Timing access caught for address %#x\n", 160 pkt->getAddr()); | 151 DPRINTF(MemoryAccess, 152 "Timing access caught for address %#x\n", pkt->getAddr()); |
161 162 //dsm: based on SimpleTimingPort::recvTiming(pkt); 163 | 153 154 //dsm: based on SimpleTimingPort::recvTiming(pkt); 155 |
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, | 156 // The received packets should only be M5 requests, which should never 157 // get nacked. There used to be code to hanldle nacks here, but 158 // 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. | 159 // 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 | 160 assert(pkt->isRequest()); 161 162 if (pkt->memInhibitAsserted()) { 163 warn("memInhibitAsserted???"); 164 // snooper will supply based on copy of packet 165 // still target's responsibility to delete packet 166 delete pkt; 167 return true; 168 } 169 |
180 // | |
181 // Save the port in the sender state object to be used later to 182 // route the response | 170 // Save the port in the sender state object to be used later to 171 // route the response |
183 // | |
184 pkt->senderState = new SenderState(this, pkt->senderState); 185 | 172 pkt->senderState = new SenderState(this, pkt->senderState); 173 |
186 // | |
187 // Check for pio requests and directly send them to the dedicated 188 // pio port. | 174 // Check for pio requests and directly send them to the dedicated 175 // pio port. |
189 // | |
190 if (!isPhysMemAddress(pkt->getAddr())) { 191 assert(ruby_port->pio_port != NULL); | 176 if (!isPhysMemAddress(pkt->getAddr())) { 177 assert(ruby_port->pio_port != NULL); |
192 DPRINTF(MemoryAccess, | 178 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 | 179 "Request for address 0x%#x is assumed to be a pio request\n", 180 pkt->getAddr()); 181 182 return ruby_port->pio_port->sendTiming(pkt); 183 } 184 |
199 // | |
200 // For DMA and CPU requests, translate them to ruby requests before 201 // sending them to our assigned ruby port. | 185 // For DMA and CPU requests, translate them to ruby requests before 186 // sending them to our assigned ruby port. |
202 // | |
203 RubyRequestType type = RubyRequestType_NULL; 204 | 187 RubyRequestType type = RubyRequestType_NULL; 188 |
205 // | |
206 // If valid, copy the pc to the ruby request | 189 // 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 { | 190 Addr pc = 0; 191 if (pkt->req->hasPC()) { 192 pc = pkt->req->getPC(); 193 } 194 195 if (pkt->isLLSC()) { 196 if (pkt->isWrite()) { 197 DPRINTF(MemoryAccess, "Issuing SC\n"); 198 type = RubyRequestType_Locked_Write; 199 } else { 200 DPRINTF(MemoryAccess, "Issuing LL\n"); 201 assert(pkt->isRead()); 202 type = RubyRequestType_Locked_Read; 203 } 204 } else { 205 if (pkt->isRead()) { 206 if (pkt->req->isInstFetch()) { 207 type = RubyRequestType_IFETCH; 208 } else { |
227 type = RubyRequestType_LD; | 209 type = RubyRequestType_LD; |
228 } 229 } else if (pkt->isWrite()) { 230 type = RubyRequestType_ST; 231 } else if (pkt->isReadWrite()) { | 210 } 211 } else if (pkt->isWrite()) { 212 type = RubyRequestType_ST; 213 } 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 // | 214 // Fix me. This conditional will never be executed 215 // because isReadWrite() is just an OR of isRead() and 216 // isWrite(). Furthermore, just because the packet is a 217 // read/write request does not necessary mean it is a 218 // read-modify-write atomic operation. |
238 type = RubyRequestType_RMW_Write; 239 } else { 240 panic("Unsupported ruby packet type\n"); 241 } 242 } 243 | 219 type = RubyRequestType_RMW_Write; 220 } else { 221 panic("Unsupported ruby packet type\n"); 222 } 223 } 224 |
244 RubyRequest ruby_request(pkt->getAddr(), 245 pkt->getPtr<uint8_t>(), 246 pkt->getSize(), 247 pc, 248 type, 249 RubyAccessMode_Supervisor, 250 pkt); | 225 RubyRequest ruby_request(pkt->getAddr(), pkt->getPtr<uint8_t>(), 226 pkt->getSize(), pc, type, 227 RubyAccessMode_Supervisor, pkt); |
251 252 // Submit the ruby request 253 RequestStatus requestStatus = ruby_port->makeRequest(ruby_request); 254 | 228 229 // Submit the ruby request 230 RequestStatus requestStatus = ruby_port->makeRequest(ruby_request); 231 |
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. | 232 // If the request successfully issued or the SC request completed because 233 // exclusive permission was lost, then we should return true. 234 // Otherwise, we need to delete the senderStatus we just created and return 235 // false. |
260 // | |
261 if ((requestStatus == RequestStatus_Issued) || 262 (requestStatus == RequestStatus_LlscFailed)) { 263 | 236 if ((requestStatus == RequestStatus_Issued) || 237 (requestStatus == RequestStatus_LlscFailed)) { 238 |
264 // | |
265 // The communicate to M5 whether the SC command succeeded by seting the 266 // packet's extra data. | 239 // The communicate to M5 whether the SC command succeeded by seting the 240 // 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 | 241 if (pkt->isLLSC() && pkt->isWrite()) { 242 if (requestStatus == RequestStatus_LlscFailed) { 243 DPRINTF(MemoryAccess, "SC failed and request completed\n"); 244 pkt->req->setExtraData(0); 245 } else { 246 pkt->req->setExtraData(1); 247 } 248 } 249 return true; 250 } 251 |
279 DPRINTF(MemoryAccess, | 252 DPRINTF(MemoryAccess, |
280 "Request for address #x did not issue because %s\n", | 253 "Request for address #x did not issue because %s\n", |
281 pkt->getAddr(), 282 RequestStatus_to_string(requestStatus)); 283 | 254 pkt->getAddr(), RequestStatus_to_string(requestStatus)); 255 |
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{ | 256 SenderState* senderState = safe_cast<SenderState*>(pkt->senderState); 257 pkt->senderState = senderState->saved; 258 delete senderState; 259 return false; 260} 261 262void 263RubyPort::ruby_hit_callback(PacketPtr pkt) 264{ |
293 // | |
294 // Retrieve the request port from the sender State | 265 // Retrieve the request port from the sender State |
295 // 296 RubyPort::SenderState *senderState = | 266 RubyPort::SenderState *senderState = |
297 safe_cast<RubyPort::SenderState *>(pkt->senderState); 298 M5Port *port = senderState->port; 299 assert(port != NULL); | 267 safe_cast<RubyPort::SenderState *>(pkt->senderState); 268 M5Port *port = senderState->port; 269 assert(port != NULL); |
300 | 270 |
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{ | 271 // pop the sender state from the packet 272 pkt->senderState = senderState->saved; 273 delete senderState; 274 275 port->hitCallback(pkt); 276} 277 278void 279RubyPort::M5Port::hitCallback(PacketPtr pkt) 280{ |
311 | |
312 bool needsResponse = pkt->needsResponse(); 313 | 281 bool needsResponse = pkt->needsResponse(); 282 |
314 DPRINTF(MemoryAccess, "Hit callback needs response %d\n", 315 needsResponse); | 283 DPRINTF(MemoryAccess, "Hit callback needs response %d\n", 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()); --- 20 unchanged lines hidden (view full) --- 344} 345 346bool 347RubyPort::M5Port::isPhysMemAddress(Addr addr) 348{ 349 AddrRangeList physMemAddrList; 350 bool snoop = false; 351 ruby_port->physMemPort->getPeerAddressRanges(physMemAddrList, snoop); | 284 285 ruby_port->physMemPort->sendAtomic(pkt); 286 287 // turn packet around to go back to requester if response expected 288 if (needsResponse) { 289 // sendAtomic() should already have turned packet into 290 // atomic response 291 assert(pkt->isResponse()); --- 20 unchanged lines hidden (view full) --- 312} 313 314bool 315RubyPort::M5Port::isPhysMemAddress(Addr addr) 316{ 317 AddrRangeList physMemAddrList; 318 bool snoop = false; 319 ruby_port->physMemPort->getPeerAddressRanges(physMemAddrList, snoop); |
352 for(AddrRangeIter iter = physMemAddrList.begin(); 353 iter != physMemAddrList.end(); 354 iter++) { | 320 for (AddrRangeIter iter = physMemAddrList.begin(); 321 iter != physMemAddrList.end(); 322 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} | 323 if (addr >= iter->start && addr <= iter->end) { 324 DPRINTF(MemoryAccess, "Request found in %#llx - %#llx range\n", 325 iter->start, iter->end); 326 return true; 327 } 328 } 329 return false; 330} |