RubyPort.cc (9814:7ad2b0186a32) | RubyPort.cc (10089:bc3126a05a7f) |
---|---|
1/* | 1/* |
2 * Copyright (c) 2012 ARM Limited | 2 * Copyright (c) 2012-2013 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 --- 36 unchanged lines hidden (view full) --- 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), | 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 --- 36 unchanged lines hidden (view full) --- 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), | 55 m_usingRubyTester(p->using_ruby_tester), |
56 drainManager(NULL), ruby_system(p->ruby_system), system(p->system), | 56 drainManager(NULL), ruby_system(p->ruby_system), system(p->system), |
57 waitingOnSequencer(false), access_phys_mem(p->access_phys_mem) | 57 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), | 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)); | 64 this, ruby_system, 65 access_phys_mem, i)); |
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} --- 41 unchanged lines hidden (view full) --- 114 } 115 116 return *slave_ports[idx]; 117 } 118} 119 120RubyPort::PioPort::PioPort(const std::string &_name, 121 RubyPort *_port) | 66 } 67 68 // create the master ports based on the number of connected ports 69 for (size_t i = 0; i < p->port_master_connection_count; ++i) { 70 master_ports.push_back(new PioPort(csprintf("%s-master%d", name(), i), 71 this)); 72 } 73} --- 41 unchanged lines hidden (view full) --- 115 } 116 117 return *slave_ports[idx]; 118 } 119} 120 121RubyPort::PioPort::PioPort(const std::string &_name, 122 RubyPort *_port) |
122 : QueuedMasterPort(_name, _port, queue), queue(*_port, *this) | 123 : QueuedMasterPort(_name, _port, queue), queue(*_port, *this), 124 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, | 125{ 126 DPRINTF(RubyPort, "creating master port on ruby sequencer %s\n", _name); 127} 128 129RubyPort::M5Port::M5Port(const std::string &_name, RubyPort *_port, |
128 RubySystem *_system, bool _access_phys_mem) 129 : QueuedSlavePort(_name, _port, queue), queue(*_port, *this), | 130 RubySystem *_system, bool _access_phys_mem, PortID id) 131 : QueuedSlavePort(_name, _port, queue, id), queue(*_port, *this), |
130 ruby_port(_port), ruby_system(_system), | 132 ruby_port(_port), ruby_system(_system), |
131 _onRetryList(false), access_phys_mem(_access_phys_mem) | 133 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 | 134{ 135 DPRINTF(RubyPort, "creating slave port on ruby sequencer %s\n", _name); 136} 137 138Tick 139RubyPort::M5Port::recvAtomic(PacketPtr pkt) 140{ 141 panic("RubyPort::M5Port::recvAtomic() not implemented!\n"); 142 return 0; 143} 144 |
143 | |
144bool | 145bool |
145RubyPort::PioPort::recvTimingResp(PacketPtr pkt) | 146RubyPort::recvTimingResp(PacketPtr pkt, PortID master_port_id) |
146{ | 147{ |
148 // got a response from a device 149 assert(pkt->isResponse()); 150 |
|
147 // In FS mode, ruby memory will receive pio responses from devices 148 // and it must forward these responses back to the particular CPU. | 151 // In FS mode, ruby memory will receive pio responses from devices 152 // and it must forward these responses back to the particular CPU. |
149 DPRINTF(RubyPort, "Pio response for address %#x\n", pkt->getAddr()); | 153 DPRINTF(RubyPort, "Pio response for address %#x, going to %d\n", 154 pkt->getAddr(), pkt->getDest()); |
150 | 155 |
151 // First we must retrieve the request port from the sender State 152 RubyPort::SenderState *senderState = 153 safe_cast<RubyPort::SenderState *>(pkt->popSenderState()); 154 M5Port *port = senderState->port; 155 assert(port != NULL); 156 delete senderState; | 156 // Retrieve the port from the destination field 157 assert(pkt->getDest() < slave_ports.size()); |
157 | 158 |
158 port->sendTimingResp(pkt); | 159 // attempt to send the response in the next cycle 160 slave_ports[pkt->getDest()]->schedTimingResp(pkt, curTick() + 161 g_system_ptr->clockPeriod()); |
159 160 return true; 161} 162 163bool 164RubyPort::M5Port::recvTimingReq(PacketPtr pkt) 165{ 166 DPRINTF(RubyPort, | 162 163 return true; 164} 165 166bool 167RubyPort::M5Port::recvTimingReq(PacketPtr pkt) 168{ 169 DPRINTF(RubyPort, |
167 "Timing access caught for address %#x\n", pkt->getAddr()); | 170 "Timing access for address %#x on port %d\n", pkt->getAddr(), 171 id); |
168 | 172 |
169 //dsm: based on SimpleTimingPort::recvTimingReq(pkt); 170 | |
171 if (pkt->memInhibitAsserted()) 172 panic("RubyPort should never see an inhibited request\n"); 173 | 173 if (pkt->memInhibitAsserted()) 174 panic("RubyPort should never see an inhibited request\n"); 175 |
174 // Save the port in the sender state object to be used later to 175 // route the response 176 pkt->pushSenderState(new SenderState(this)); | 176 // Save the port id to be used later to route the response 177 pkt->setSrc(id); |
177 178 // Check for pio requests and directly send them to the dedicated 179 // pio port. 180 if (!isPhysMemAddress(pkt->getAddr())) { 181 assert(ruby_port->pio_port.isConnected()); 182 DPRINTF(RubyPort, 183 "Request for address 0x%#x is assumed to be a pio request\n", 184 pkt->getAddr()); --- 6 unchanged lines hidden (view full) --- 191 192 assert(Address(pkt->getAddr()).getOffset() + pkt->getSize() <= 193 RubySystem::getBlockSizeBytes()); 194 195 // Submit the ruby request 196 RequestStatus requestStatus = ruby_port->makeRequest(pkt); 197 198 // If the request successfully issued then we should return true. | 178 179 // Check for pio requests and directly send them to the dedicated 180 // pio port. 181 if (!isPhysMemAddress(pkt->getAddr())) { 182 assert(ruby_port->pio_port.isConnected()); 183 DPRINTF(RubyPort, 184 "Request for address 0x%#x is assumed to be a pio request\n", 185 pkt->getAddr()); --- 6 unchanged lines hidden (view full) --- 192 193 assert(Address(pkt->getAddr()).getOffset() + pkt->getSize() <= 194 RubySystem::getBlockSizeBytes()); 195 196 // Submit the ruby request 197 RequestStatus requestStatus = ruby_port->makeRequest(pkt); 198 199 // If the request successfully issued then we should return true. |
199 // Otherwise, we need to delete the senderStatus we just created and return 200 // false. | 200 // Otherwise, we need to tell the port to retry at a later point 201 // and return false. |
201 if (requestStatus == RequestStatus_Issued) { | 202 if (requestStatus == RequestStatus_Issued) { |
202 DPRINTF(RubyPort, "Request %#x issued\n", pkt->getAddr()); | 203 DPRINTF(RubyPort, "Request %s 0x%x issued\n", pkt->cmdString(), 204 pkt->getAddr()); |
203 return true; 204 } 205 206 // 207 // Unless one is using the ruby tester, record the stalled M5 port for 208 // later retry when the sequencer becomes free. 209 // 210 if (!ruby_port->m_usingRubyTester) { 211 ruby_port->addToRetryList(this); 212 } 213 214 DPRINTF(RubyPort, 215 "Request for address %#x did not issue because %s\n", 216 pkt->getAddr(), RequestStatus_to_string(requestStatus)); 217 | 205 return true; 206 } 207 208 // 209 // Unless one is using the ruby tester, record the stalled M5 port for 210 // later retry when the sequencer becomes free. 211 // 212 if (!ruby_port->m_usingRubyTester) { 213 ruby_port->addToRetryList(this); 214 } 215 216 DPRINTF(RubyPort, 217 "Request for address %#x did not issue because %s\n", 218 pkt->getAddr(), RequestStatus_to_string(requestStatus)); 219 |
218 SenderState* senderState = safe_cast<SenderState*>(pkt->senderState); 219 pkt->senderState = senderState->predecessor; 220 delete senderState; | |
221 return false; 222} 223 224void 225RubyPort::M5Port::recvFunctional(PacketPtr pkt) 226{ 227 DPRINTF(RubyPort, "Functional access caught for address %#x\n", 228 pkt->getAddr()); --- 50 unchanged lines hidden (view full) --- 279 } 280 DPRINTF(RubyPort, "Functional access %s!\n", 281 accessSucceeded ? "successful":"failed"); 282} 283 284void 285RubyPort::ruby_hit_callback(PacketPtr pkt) 286{ | 220 return false; 221} 222 223void 224RubyPort::M5Port::recvFunctional(PacketPtr pkt) 225{ 226 DPRINTF(RubyPort, "Functional access caught for address %#x\n", 227 pkt->getAddr()); --- 50 unchanged lines hidden (view full) --- 278 } 279 DPRINTF(RubyPort, "Functional access %s!\n", 280 accessSucceeded ? "successful":"failed"); 281} 282 283void 284RubyPort::ruby_hit_callback(PacketPtr pkt) 285{ |
287 // Retrieve the request port from the sender State 288 RubyPort::SenderState *senderState = 289 safe_cast<RubyPort::SenderState *>(pkt->senderState); 290 M5Port *port = senderState->port; 291 assert(port != NULL); | 286 DPRINTF(RubyPort, "Hit callback for %s 0x%x\n", pkt->cmdString(), 287 pkt->getAddr()); |
292 | 288 |
293 // pop the sender state from the packet 294 pkt->senderState = senderState->predecessor; 295 delete senderState; | 289 // The packet was destined for memory and has not yet been turned 290 // into a response 291 assert(system->isMemAddr(pkt->getAddr())); 292 assert(pkt->isRequest()); |
296 | 293 |
297 port->hitCallback(pkt); | 294 // As it has not yet been turned around, the source field tells us 295 // which port it came from. 296 assert(pkt->getSrc() < slave_ports.size()); |
298 | 297 |
298 slave_ports[pkt->getSrc()]->hitCallback(pkt); 299 |
|
299 // 300 // If we had to stall the M5Ports, wake them up because the sequencer 301 // likely has free resources now. 302 // | 300 // 301 // If we had to stall the M5Ports, wake them up because the sequencer 302 // likely has free resources now. 303 // |
303 if (waitingOnSequencer) { | 304 if (!retryList.empty()) { |
304 // 305 // Record the current list of ports to retry on a temporary list before 306 // calling sendRetry on those ports. sendRetry will cause an 307 // immediate retry, which may result in the ports being put back on the 308 // list. Therefore we want to clear the retryList before calling 309 // sendRetry. 310 // | 305 // 306 // Record the current list of ports to retry on a temporary list before 307 // calling sendRetry on those ports. sendRetry will cause an 308 // immediate retry, which may result in the ports being put back on the 309 // list. Therefore we want to clear the retryList before calling 310 // sendRetry. 311 // |
311 std::list<M5Port*> curRetryList(retryList); | 312 std::vector<M5Port*> curRetryList(retryList); |
312 313 retryList.clear(); | 313 314 retryList.clear(); |
314 waitingOnSequencer = false; 315 316 for (std::list<M5Port*>::iterator i = curRetryList.begin(); 317 i != curRetryList.end(); ++i) { | 315 316 for (auto i = curRetryList.begin(); i != curRetryList.end(); ++i) { |
318 DPRINTF(RubyPort, 319 "Sequencer may now be free. SendRetry to port %s\n", 320 (*i)->name()); | 317 DPRINTF(RubyPort, 318 "Sequencer may now be free. SendRetry to port %s\n", 319 (*i)->name()); |
321 (*i)->onRetryList(false); | |
322 (*i)->sendRetry(); 323 } 324 } 325 326 testDrainComplete(); 327} 328 329void --- 136 unchanged lines hidden (view full) --- 466RubyPort::M5Port::getAddrRanges() const 467{ 468 // at the moment the assumption is that the master does not care 469 AddrRangeList ranges; 470 return ranges; 471} 472 473bool | 320 (*i)->sendRetry(); 321 } 322 } 323 324 testDrainComplete(); 325} 326 327void --- 136 unchanged lines hidden (view full) --- 464RubyPort::M5Port::getAddrRanges() const 465{ 466 // at the moment the assumption is that the master does not care 467 AddrRangeList ranges; 468 return ranges; 469} 470 471bool |
474RubyPort::M5Port::isPhysMemAddress(Addr addr) | 472RubyPort::M5Port::isPhysMemAddress(Addr addr) const |
475{ 476 return ruby_port->system->isMemAddr(addr); 477} 478 479void 480RubyPort::ruby_eviction_callback(const Address& address) 481{ 482 DPRINTF(RubyPort, "Sending invalidations.\n"); --- 16 unchanged lines hidden --- | 473{ 474 return ruby_port->system->isMemAddr(addr); 475} 476 477void 478RubyPort::ruby_eviction_callback(const Address& address) 479{ 480 DPRINTF(RubyPort, "Sending invalidations.\n"); --- 16 unchanged lines hidden --- |