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 ---