RubyPort.cc (8161:ebb373fcb206) RubyPort.cc (8162:5f69f1b0039e)
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;
9 * redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution;
12 * neither the name of the copyright holders nor the names of its
13 * contributors may be used to endorse or promote products derived from
14 * this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
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 "config/the_isa.hh"
30#if THE_ISA == X86_ISA
31#include "arch/x86/insts/microldstop.hh"
32#endif // X86_ISA
33#include "cpu/testers/rubytest/RubyTester.hh"
34#include "mem/physical.hh"
35#include "mem/ruby/slicc_interface/AbstractController.hh"
36#include "mem/ruby/system/RubyPort.hh"
37
38RubyPort::RubyPort(const Params *p)
39 : MemObject(p)
40{
41 m_version = p->version;
42 assert(m_version != -1);
43
44 physmem = p->physmem;
45
46 m_controller = NULL;
47 m_mandatory_q_ptr = NULL;
48
49 m_request_cnt = 0;
50 pio_port = NULL;
51 physMemPort = NULL;
52
53 m_usingRubyTester = p->using_ruby_tester;
54 access_phys_mem = p->access_phys_mem;
55}
56
57void
58RubyPort::init()
59{
60 assert(m_controller != NULL);
61 m_mandatory_q_ptr = m_controller->getMandatoryQueue();
62}
63
64Port *
65RubyPort::getPort(const std::string &if_name, int idx)
66{
67 if (if_name == "port") {
68 return new M5Port(csprintf("%s-port%d", name(), idx), this,
69 access_phys_mem);
70 }
71
72 if (if_name == "pio_port") {
73 // ensure there is only one pio port
74 assert(pio_port == NULL);
75
76 pio_port = new PioPort(csprintf("%s-pio-port%d", name(), idx), this);
77
78 return pio_port;
79 }
80
81 if (if_name == "physMemPort") {
82 // RubyPort should only have one port to physical memory
83 assert (physMemPort == NULL);
84
85 physMemPort = new M5Port(csprintf("%s-physMemPort", name()), this,
86 access_phys_mem);
87
88 return physMemPort;
89 }
90
91 if (if_name == "functional") {
92 // Calls for the functional port only want to access
93 // functional memory. Therefore, directly pass these calls
94 // ports to physmem.
95 assert(physmem != NULL);
96 return physmem->getPort(if_name, idx);
97 }
98
99 return NULL;
100}
101
102RubyPort::PioPort::PioPort(const std::string &_name,
103 RubyPort *_port)
104 : SimpleTimingPort(_name, _port)
105{
106 DPRINTF(RubyPort, "creating port to ruby sequencer to cpu %s\n", _name);
107 ruby_port = _port;
108}
109
110RubyPort::M5Port::M5Port(const std::string &_name,
111 RubyPort *_port, bool _access_phys_mem)
112 : SimpleTimingPort(_name, _port)
113{
114 DPRINTF(RubyPort, "creating port from ruby sequcner to cpu %s\n", _name);
115 ruby_port = _port;
116 _onRetryList = false;
117 access_phys_mem = _access_phys_mem;
118}
119
120Tick
121RubyPort::PioPort::recvAtomic(PacketPtr pkt)
122{
123 panic("RubyPort::PioPort::recvAtomic() not implemented!\n");
124 return 0;
125}
126
127Tick
128RubyPort::M5Port::recvAtomic(PacketPtr pkt)
129{
130 panic("RubyPort::M5Port::recvAtomic() not implemented!\n");
131 return 0;
132}
133
134
135bool
136RubyPort::PioPort::recvTiming(PacketPtr pkt)
137{
138 // In FS mode, ruby memory will receive pio responses from devices
139 // and it must forward these responses back to the particular CPU.
140 DPRINTF(RubyPort, "Pio response for address %#x\n", pkt->getAddr());
141
142 assert(pkt->isResponse());
143
144 // First we must retrieve the request port from the sender State
145 RubyPort::SenderState *senderState =
146 safe_cast<RubyPort::SenderState *>(pkt->senderState);
147 M5Port *port = senderState->port;
148 assert(port != NULL);
149
150 // pop the sender state from the packet
151 pkt->senderState = senderState->saved;
152 delete senderState;
153
154 port->sendTiming(pkt);
155
156 return true;
157}
158
159bool
160RubyPort::M5Port::recvTiming(PacketPtr pkt)
161{
162 DPRINTF(RubyPort,
163 "Timing access caught for address %#x\n", pkt->getAddr());
164
165 //dsm: based on SimpleTimingPort::recvTiming(pkt);
166
167 // The received packets should only be M5 requests, which should never
168 // get nacked. There used to be code to hanldle nacks here, but
169 // I'm pretty sure it didn't work correctly with the drain code,
170 // so that would need to be fixed if we ever added it back.
171 assert(pkt->isRequest());
172
173 if (pkt->memInhibitAsserted()) {
174 warn("memInhibitAsserted???");
175 // snooper will supply based on copy of packet
176 // still target's responsibility to delete packet
177 delete pkt;
178 return true;
179 }
180
181 // Save the port in the sender state object to be used later to
182 // route the response
183 pkt->senderState = new SenderState(this, pkt->senderState);
184
185 // Check for pio requests and directly send them to the dedicated
186 // pio port.
187 if (!isPhysMemAddress(pkt->getAddr())) {
188 assert(ruby_port->pio_port != NULL);
189 DPRINTF(RubyPort,
190 "Request for address 0x%#x is assumed to be a pio request\n",
191 pkt->getAddr());
192
193 return ruby_port->pio_port->sendTiming(pkt);
194 }
195
196 // For DMA and CPU requests, translate them to ruby requests before
197 // sending them to our assigned ruby port.
198 RubyRequestType type = RubyRequestType_NULL;
199
200 // If valid, copy the pc to the ruby request
201 Addr pc = 0;
202 if (pkt->req->hasPC()) {
203 pc = pkt->req->getPC();
204 }
205
206 if (pkt->isLLSC()) {
207 if (pkt->isWrite()) {
208 DPRINTF(RubyPort, "Issuing SC\n");
209 type = RubyRequestType_Store_Conditional;
210 } else {
211 DPRINTF(RubyPort, "Issuing LL\n");
212 assert(pkt->isRead());
213 type = RubyRequestType_Load_Linked;
214 }
215 } else if (pkt->req->isLocked()) {
216 if (pkt->isWrite()) {
217 DPRINTF(RubyPort, "Issuing Locked RMW Write\n");
218 type = RubyRequestType_Locked_RMW_Write;
219 } else {
220 DPRINTF(RubyPort, "Issuing Locked RMW Read\n");
221 assert(pkt->isRead());
222 type = RubyRequestType_Locked_RMW_Read;
223 }
224 } else {
225 if (pkt->isRead()) {
226 if (pkt->req->isInstFetch()) {
227 type = RubyRequestType_IFETCH;
228 } else {
229#if THE_ISA == X86_ISA
230 uint32_t flags = pkt->req->getFlags();
231 bool storeCheck = flags &
232 (TheISA::StoreCheck << TheISA::FlagShift);
233#else
234 bool storeCheck = false;
235#endif // X86_ISA
236 if (storeCheck) {
237 type = RubyRequestType_RMW_Read;
238 } else {
239 type = RubyRequestType_LD;
240 }
241 }
242 } else if (pkt->isWrite()) {
243 //
244 // Note: M5 packets do not differentiate ST from RMW_Write
245 //
246 type = RubyRequestType_ST;
247 } else {
248 panic("Unsupported ruby packet type\n");
249 }
250 }
251
252 RubyRequest ruby_request(pkt->getAddr(), pkt->getPtr<uint8_t>(true),
253 pkt->getSize(), pc, type,
254 RubyAccessMode_Supervisor, pkt);
255
256 assert(Address(ruby_request.paddr).getOffset() + ruby_request.len <=
257 RubySystem::getBlockSizeBytes());
258
259 // Submit the ruby request
260 RequestStatus requestStatus = ruby_port->makeRequest(ruby_request);
261
262 // If the request successfully issued then we should return true.
263 // Otherwise, we need to delete the senderStatus we just created and return
264 // false.
265 if (requestStatus == RequestStatus_Issued) {
266 DPRINTF(RubyPort, "Request %#x issued\n", pkt->getAddr());
267 return true;
268 }
269
270 //
271 // Unless one is using the ruby tester, record the stalled M5 port for
272 // later retry when the sequencer becomes free.
273 //
274 if (!ruby_port->m_usingRubyTester) {
275 ruby_port->addToRetryList(this);
276 }
277
278 DPRINTF(RubyPort,
279 "Request for address %#x did not issue because %s\n",
280 pkt->getAddr(), RequestStatus_to_string(requestStatus));
281
282 SenderState* senderState = safe_cast<SenderState*>(pkt->senderState);
283 pkt->senderState = senderState->saved;
284 delete senderState;
285 return false;
286}
287
288void
289RubyPort::ruby_hit_callback(PacketPtr pkt)
290{
291 // Retrieve the request port from the sender State
292 RubyPort::SenderState *senderState =
293 safe_cast<RubyPort::SenderState *>(pkt->senderState);
294 M5Port *port = senderState->port;
295 assert(port != NULL);
296
297 // pop the sender state from the packet
298 pkt->senderState = senderState->saved;
299 delete senderState;
300
301 port->hitCallback(pkt);
302
303 //
304 // If we had to stall the M5Ports, wake them up because the sequencer
305 // likely has free resources now.
306 //
307 if (waitingOnSequencer) {
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;
9 * redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution;
12 * neither the name of the copyright holders nor the names of its
13 * contributors may be used to endorse or promote products derived from
14 * this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
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 "config/the_isa.hh"
30#if THE_ISA == X86_ISA
31#include "arch/x86/insts/microldstop.hh"
32#endif // X86_ISA
33#include "cpu/testers/rubytest/RubyTester.hh"
34#include "mem/physical.hh"
35#include "mem/ruby/slicc_interface/AbstractController.hh"
36#include "mem/ruby/system/RubyPort.hh"
37
38RubyPort::RubyPort(const Params *p)
39 : MemObject(p)
40{
41 m_version = p->version;
42 assert(m_version != -1);
43
44 physmem = p->physmem;
45
46 m_controller = NULL;
47 m_mandatory_q_ptr = NULL;
48
49 m_request_cnt = 0;
50 pio_port = NULL;
51 physMemPort = NULL;
52
53 m_usingRubyTester = p->using_ruby_tester;
54 access_phys_mem = p->access_phys_mem;
55}
56
57void
58RubyPort::init()
59{
60 assert(m_controller != NULL);
61 m_mandatory_q_ptr = m_controller->getMandatoryQueue();
62}
63
64Port *
65RubyPort::getPort(const std::string &if_name, int idx)
66{
67 if (if_name == "port") {
68 return new M5Port(csprintf("%s-port%d", name(), idx), this,
69 access_phys_mem);
70 }
71
72 if (if_name == "pio_port") {
73 // ensure there is only one pio port
74 assert(pio_port == NULL);
75
76 pio_port = new PioPort(csprintf("%s-pio-port%d", name(), idx), this);
77
78 return pio_port;
79 }
80
81 if (if_name == "physMemPort") {
82 // RubyPort should only have one port to physical memory
83 assert (physMemPort == NULL);
84
85 physMemPort = new M5Port(csprintf("%s-physMemPort", name()), this,
86 access_phys_mem);
87
88 return physMemPort;
89 }
90
91 if (if_name == "functional") {
92 // Calls for the functional port only want to access
93 // functional memory. Therefore, directly pass these calls
94 // ports to physmem.
95 assert(physmem != NULL);
96 return physmem->getPort(if_name, idx);
97 }
98
99 return NULL;
100}
101
102RubyPort::PioPort::PioPort(const std::string &_name,
103 RubyPort *_port)
104 : SimpleTimingPort(_name, _port)
105{
106 DPRINTF(RubyPort, "creating port to ruby sequencer to cpu %s\n", _name);
107 ruby_port = _port;
108}
109
110RubyPort::M5Port::M5Port(const std::string &_name,
111 RubyPort *_port, bool _access_phys_mem)
112 : SimpleTimingPort(_name, _port)
113{
114 DPRINTF(RubyPort, "creating port from ruby sequcner to cpu %s\n", _name);
115 ruby_port = _port;
116 _onRetryList = false;
117 access_phys_mem = _access_phys_mem;
118}
119
120Tick
121RubyPort::PioPort::recvAtomic(PacketPtr pkt)
122{
123 panic("RubyPort::PioPort::recvAtomic() not implemented!\n");
124 return 0;
125}
126
127Tick
128RubyPort::M5Port::recvAtomic(PacketPtr pkt)
129{
130 panic("RubyPort::M5Port::recvAtomic() not implemented!\n");
131 return 0;
132}
133
134
135bool
136RubyPort::PioPort::recvTiming(PacketPtr pkt)
137{
138 // In FS mode, ruby memory will receive pio responses from devices
139 // and it must forward these responses back to the particular CPU.
140 DPRINTF(RubyPort, "Pio response for address %#x\n", pkt->getAddr());
141
142 assert(pkt->isResponse());
143
144 // First we must retrieve the request port from the sender State
145 RubyPort::SenderState *senderState =
146 safe_cast<RubyPort::SenderState *>(pkt->senderState);
147 M5Port *port = senderState->port;
148 assert(port != NULL);
149
150 // pop the sender state from the packet
151 pkt->senderState = senderState->saved;
152 delete senderState;
153
154 port->sendTiming(pkt);
155
156 return true;
157}
158
159bool
160RubyPort::M5Port::recvTiming(PacketPtr pkt)
161{
162 DPRINTF(RubyPort,
163 "Timing access caught for address %#x\n", pkt->getAddr());
164
165 //dsm: based on SimpleTimingPort::recvTiming(pkt);
166
167 // The received packets should only be M5 requests, which should never
168 // get nacked. There used to be code to hanldle nacks here, but
169 // I'm pretty sure it didn't work correctly with the drain code,
170 // so that would need to be fixed if we ever added it back.
171 assert(pkt->isRequest());
172
173 if (pkt->memInhibitAsserted()) {
174 warn("memInhibitAsserted???");
175 // snooper will supply based on copy of packet
176 // still target's responsibility to delete packet
177 delete pkt;
178 return true;
179 }
180
181 // Save the port in the sender state object to be used later to
182 // route the response
183 pkt->senderState = new SenderState(this, pkt->senderState);
184
185 // Check for pio requests and directly send them to the dedicated
186 // pio port.
187 if (!isPhysMemAddress(pkt->getAddr())) {
188 assert(ruby_port->pio_port != NULL);
189 DPRINTF(RubyPort,
190 "Request for address 0x%#x is assumed to be a pio request\n",
191 pkt->getAddr());
192
193 return ruby_port->pio_port->sendTiming(pkt);
194 }
195
196 // For DMA and CPU requests, translate them to ruby requests before
197 // sending them to our assigned ruby port.
198 RubyRequestType type = RubyRequestType_NULL;
199
200 // If valid, copy the pc to the ruby request
201 Addr pc = 0;
202 if (pkt->req->hasPC()) {
203 pc = pkt->req->getPC();
204 }
205
206 if (pkt->isLLSC()) {
207 if (pkt->isWrite()) {
208 DPRINTF(RubyPort, "Issuing SC\n");
209 type = RubyRequestType_Store_Conditional;
210 } else {
211 DPRINTF(RubyPort, "Issuing LL\n");
212 assert(pkt->isRead());
213 type = RubyRequestType_Load_Linked;
214 }
215 } else if (pkt->req->isLocked()) {
216 if (pkt->isWrite()) {
217 DPRINTF(RubyPort, "Issuing Locked RMW Write\n");
218 type = RubyRequestType_Locked_RMW_Write;
219 } else {
220 DPRINTF(RubyPort, "Issuing Locked RMW Read\n");
221 assert(pkt->isRead());
222 type = RubyRequestType_Locked_RMW_Read;
223 }
224 } else {
225 if (pkt->isRead()) {
226 if (pkt->req->isInstFetch()) {
227 type = RubyRequestType_IFETCH;
228 } else {
229#if THE_ISA == X86_ISA
230 uint32_t flags = pkt->req->getFlags();
231 bool storeCheck = flags &
232 (TheISA::StoreCheck << TheISA::FlagShift);
233#else
234 bool storeCheck = false;
235#endif // X86_ISA
236 if (storeCheck) {
237 type = RubyRequestType_RMW_Read;
238 } else {
239 type = RubyRequestType_LD;
240 }
241 }
242 } else if (pkt->isWrite()) {
243 //
244 // Note: M5 packets do not differentiate ST from RMW_Write
245 //
246 type = RubyRequestType_ST;
247 } else {
248 panic("Unsupported ruby packet type\n");
249 }
250 }
251
252 RubyRequest ruby_request(pkt->getAddr(), pkt->getPtr<uint8_t>(true),
253 pkt->getSize(), pc, type,
254 RubyAccessMode_Supervisor, pkt);
255
256 assert(Address(ruby_request.paddr).getOffset() + ruby_request.len <=
257 RubySystem::getBlockSizeBytes());
258
259 // Submit the ruby request
260 RequestStatus requestStatus = ruby_port->makeRequest(ruby_request);
261
262 // If the request successfully issued then we should return true.
263 // Otherwise, we need to delete the senderStatus we just created and return
264 // false.
265 if (requestStatus == RequestStatus_Issued) {
266 DPRINTF(RubyPort, "Request %#x issued\n", pkt->getAddr());
267 return true;
268 }
269
270 //
271 // Unless one is using the ruby tester, record the stalled M5 port for
272 // later retry when the sequencer becomes free.
273 //
274 if (!ruby_port->m_usingRubyTester) {
275 ruby_port->addToRetryList(this);
276 }
277
278 DPRINTF(RubyPort,
279 "Request for address %#x did not issue because %s\n",
280 pkt->getAddr(), RequestStatus_to_string(requestStatus));
281
282 SenderState* senderState = safe_cast<SenderState*>(pkt->senderState);
283 pkt->senderState = senderState->saved;
284 delete senderState;
285 return false;
286}
287
288void
289RubyPort::ruby_hit_callback(PacketPtr pkt)
290{
291 // Retrieve the request port from the sender State
292 RubyPort::SenderState *senderState =
293 safe_cast<RubyPort::SenderState *>(pkt->senderState);
294 M5Port *port = senderState->port;
295 assert(port != NULL);
296
297 // pop the sender state from the packet
298 pkt->senderState = senderState->saved;
299 delete senderState;
300
301 port->hitCallback(pkt);
302
303 //
304 // If we had to stall the M5Ports, wake them up because the sequencer
305 // likely has free resources now.
306 //
307 if (waitingOnSequencer) {
308 for (std::list<M5Port*>::iterator i = retryList.begin();
309 i != retryList.end(); ++i) {
310 (*i)->sendRetry();
311 (*i)->onRetryList(false);
312 DPRINTF(MemoryAccess,
308 //
309 // Record the current list of ports to retry on a temporary list before
310 // calling sendRetry on those ports. sendRetry will cause an
311 // immediate retry, which may result in the ports being put back on the
312 // list. Therefore we want to clear the retryList before calling
313 // sendRetry.
314 //
315 std::list<M5Port*> curRetryList(retryList);
316
317 retryList.clear();
318 waitingOnSequencer = false;
319
320 for (std::list<M5Port*>::iterator i = curRetryList.begin();
321 i != curRetryList.end(); ++i) {
322 DPRINTF(RubyPort,
313 "Sequencer may now be free. SendRetry to port %s\n",
314 (*i)->name());
323 "Sequencer may now be free. SendRetry to port %s\n",
324 (*i)->name());
325 (*i)->onRetryList(false);
326 (*i)->sendRetry();
315 }
327 }
316 retryList.clear();
317 waitingOnSequencer = false;
318 }
319}
320
321void
322RubyPort::M5Port::hitCallback(PacketPtr pkt)
323{
324 bool needsResponse = pkt->needsResponse();
325
326 //
327 // Unless specified at configuraiton, all responses except failed SC
328 // operations access M5 physical memory.
329 //
330 bool accessPhysMem = access_phys_mem;
331
332 if (pkt->isLLSC()) {
333 if (pkt->isWrite()) {
334 if (pkt->req->getExtraData() != 0) {
335 //
336 // Successful SC packets convert to normal writes
337 //
338 pkt->convertScToWrite();
339 } else {
340 //
341 // Failed SC packets don't access physical memory and thus
342 // the RubyPort itself must convert it to a response.
343 //
344 accessPhysMem = false;
345 }
346 } else {
347 //
348 // All LL packets convert to normal loads so that M5 PhysMem does
349 // not lock the blocks.
350 //
351 pkt->convertLlToRead();
352 }
353 }
354 DPRINTF(RubyPort, "Hit callback needs response %d\n", needsResponse);
355
356 if (accessPhysMem) {
357 ruby_port->physMemPort->sendAtomic(pkt);
358 } else {
359 pkt->makeResponse();
360 }
361
362 // turn packet around to go back to requester if response expected
363 if (needsResponse) {
364 DPRINTF(RubyPort, "Sending packet back over port\n");
365 sendTiming(pkt);
366 } else {
367 delete pkt;
368 }
369 DPRINTF(RubyPort, "Hit callback done!\n");
370}
371
372bool
373RubyPort::M5Port::sendTiming(PacketPtr pkt)
374{
375 //minimum latency, must be > 0
376 schedSendTiming(pkt, curTick() + (1 * g_eventQueue_ptr->getClock()));
377 return true;
378}
379
380bool
381RubyPort::PioPort::sendTiming(PacketPtr pkt)
382{
383 //minimum latency, must be > 0
384 schedSendTiming(pkt, curTick() + (1 * g_eventQueue_ptr->getClock()));
385 return true;
386}
387
388bool
389RubyPort::M5Port::isPhysMemAddress(Addr addr)
390{
391 AddrRangeList physMemAddrList;
392 bool snoop = false;
393 ruby_port->physMemPort->getPeerAddressRanges(physMemAddrList, snoop);
394 for (AddrRangeIter iter = physMemAddrList.begin();
395 iter != physMemAddrList.end();
396 iter++) {
397 if (addr >= iter->start && addr <= iter->end) {
398 DPRINTF(RubyPort, "Request found in %#llx - %#llx range\n",
399 iter->start, iter->end);
400 return true;
401 }
402 }
403 return false;
404}
405
406unsigned
407RubyPort::M5Port::deviceBlockSize() const
408{
409 return (unsigned) RubySystem::getBlockSizeBytes();
410}
328 }
329}
330
331void
332RubyPort::M5Port::hitCallback(PacketPtr pkt)
333{
334 bool needsResponse = pkt->needsResponse();
335
336 //
337 // Unless specified at configuraiton, all responses except failed SC
338 // operations access M5 physical memory.
339 //
340 bool accessPhysMem = access_phys_mem;
341
342 if (pkt->isLLSC()) {
343 if (pkt->isWrite()) {
344 if (pkt->req->getExtraData() != 0) {
345 //
346 // Successful SC packets convert to normal writes
347 //
348 pkt->convertScToWrite();
349 } else {
350 //
351 // Failed SC packets don't access physical memory and thus
352 // the RubyPort itself must convert it to a response.
353 //
354 accessPhysMem = false;
355 }
356 } else {
357 //
358 // All LL packets convert to normal loads so that M5 PhysMem does
359 // not lock the blocks.
360 //
361 pkt->convertLlToRead();
362 }
363 }
364 DPRINTF(RubyPort, "Hit callback needs response %d\n", needsResponse);
365
366 if (accessPhysMem) {
367 ruby_port->physMemPort->sendAtomic(pkt);
368 } else {
369 pkt->makeResponse();
370 }
371
372 // turn packet around to go back to requester if response expected
373 if (needsResponse) {
374 DPRINTF(RubyPort, "Sending packet back over port\n");
375 sendTiming(pkt);
376 } else {
377 delete pkt;
378 }
379 DPRINTF(RubyPort, "Hit callback done!\n");
380}
381
382bool
383RubyPort::M5Port::sendTiming(PacketPtr pkt)
384{
385 //minimum latency, must be > 0
386 schedSendTiming(pkt, curTick() + (1 * g_eventQueue_ptr->getClock()));
387 return true;
388}
389
390bool
391RubyPort::PioPort::sendTiming(PacketPtr pkt)
392{
393 //minimum latency, must be > 0
394 schedSendTiming(pkt, curTick() + (1 * g_eventQueue_ptr->getClock()));
395 return true;
396}
397
398bool
399RubyPort::M5Port::isPhysMemAddress(Addr addr)
400{
401 AddrRangeList physMemAddrList;
402 bool snoop = false;
403 ruby_port->physMemPort->getPeerAddressRanges(physMemAddrList, snoop);
404 for (AddrRangeIter iter = physMemAddrList.begin();
405 iter != physMemAddrList.end();
406 iter++) {
407 if (addr >= iter->start && addr <= iter->end) {
408 DPRINTF(RubyPort, "Request found in %#llx - %#llx range\n",
409 iter->start, iter->end);
410 return true;
411 }
412 }
413 return false;
414}
415
416unsigned
417RubyPort::M5Port::deviceBlockSize() const
418{
419 return (unsigned) RubySystem::getBlockSizeBytes();
420}