Packet: Unify the use of PortID in packet and port
[gem5.git] / src / mem / bus.cc
1 /*
2 * Copyright (c) 2011-2012 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
11 * unmodified and in its entirety in all distributions of the software,
12 * modified or unmodified, in source code or in binary form.
13 *
14 * Copyright (c) 2006 The Regents of The University of Michigan
15 * All rights reserved.
16 *
17 * Redistribution and use in source and binary forms, with or without
18 * modification, are permitted provided that the following conditions are
19 * met: redistributions of source code must retain the above copyright
20 * notice, this list of conditions and the following disclaimer;
21 * redistributions in binary form must reproduce the above copyright
22 * notice, this list of conditions and the following disclaimer in the
23 * documentation and/or other materials provided with the distribution;
24 * neither the name of the copyright holders nor the names of its
25 * contributors may be used to endorse or promote products derived from
26 * this software without specific prior written permission.
27 *
28 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
29 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
30 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
31 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
32 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
33 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
34 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
35 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
36 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
37 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
38 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
39 *
40 * Authors: Ali Saidi
41 * Andreas Hansson
42 * William Wang
43 */
44
45 /**
46 * @file
47 * Definition of a bus object.
48 */
49
50 #include "base/misc.hh"
51 #include "base/trace.hh"
52 #include "debug/Bus.hh"
53 #include "debug/BusAddrRanges.hh"
54 #include "mem/bus.hh"
55
56 Bus::Bus(const BusParams *p)
57 : MemObject(p), clock(p->clock),
58 headerCycles(p->header_cycles), width(p->width), tickNextIdle(0),
59 drainEvent(NULL), busIdleEvent(this), inRetry(false),
60 defaultPortID(InvalidPortID),
61 useDefaultRange(p->use_default_range),
62 defaultBlockSize(p->block_size),
63 cachedBlockSize(0), cachedBlockSizeValid(false)
64 {
65 //width, clock period, and header cycles must be positive
66 if (width <= 0)
67 fatal("Bus width must be positive\n");
68 if (clock <= 0)
69 fatal("Bus clock period must be positive\n");
70 if (headerCycles <= 0)
71 fatal("Number of header cycles must be positive\n");
72
73 // create the ports based on the size of the master and slave
74 // vector ports, and the presence of the default port, the ports
75 // are enumerated starting from zero
76 for (int i = 0; i < p->port_master_connection_count; ++i) {
77 std::string portName = csprintf("%s-p%d", name(), i);
78 MasterPort* bp = new BusMasterPort(portName, this, i);
79 masterPorts.push_back(bp);
80 }
81
82 // see if we have a default slave device connected and if so add
83 // our corresponding master port
84 if (p->port_default_connection_count) {
85 defaultPortID = masterPorts.size();
86 std::string portName = csprintf("%s-default", name());
87 MasterPort* bp = new BusMasterPort(portName, this, defaultPortID);
88 masterPorts.push_back(bp);
89 }
90
91 // create the slave ports, once again starting at zero
92 for (int i = 0; i < p->port_slave_connection_count; ++i) {
93 std::string portName = csprintf("%s-p%d", name(), i);
94 SlavePort* bp = new BusSlavePort(portName, this, i);
95 slavePorts.push_back(bp);
96 }
97
98 clearPortCache();
99 }
100
101 MasterPort &
102 Bus::getMasterPort(const std::string &if_name, int idx)
103 {
104 if (if_name == "master" && idx < masterPorts.size()) {
105 // the master port index translates directly to the vector position
106 return *masterPorts[idx];
107 } else if (if_name == "default") {
108 return *masterPorts[defaultPortID];
109 } else {
110 return MemObject::getMasterPort(if_name, idx);
111 }
112 }
113
114 SlavePort &
115 Bus::getSlavePort(const std::string &if_name, int idx)
116 {
117 if (if_name == "slave" && idx < slavePorts.size()) {
118 // the slave port index translates directly to the vector position
119 return *slavePorts[idx];
120 } else {
121 return MemObject::getSlavePort(if_name, idx);
122 }
123 }
124
125 void
126 Bus::init()
127 {
128 // iterate over our slave ports and determine which of our
129 // neighbouring master ports are snooping and add them as snoopers
130 for (SlavePortConstIter p = slavePorts.begin(); p != slavePorts.end();
131 ++p) {
132 if ((*p)->getMasterPort().isSnooping()) {
133 DPRINTF(BusAddrRanges, "Adding snooping neighbour %s\n",
134 (*p)->getMasterPort().name());
135 snoopPorts.push_back(*p);
136 }
137 }
138 }
139
140 Tick
141 Bus::calcPacketTiming(PacketPtr pkt)
142 {
143 // determine the current time rounded to the closest following
144 // clock edge
145 Tick now = curTick();
146 if (now % clock != 0) {
147 now = ((now / clock) + 1) * clock;
148 }
149
150 Tick headerTime = now + headerCycles * clock;
151
152 // The packet will be sent. Figure out how long it occupies the bus, and
153 // how much of that time is for the first "word", aka bus width.
154 int numCycles = 0;
155 if (pkt->hasData()) {
156 // If a packet has data, it needs ceil(size/width) cycles to send it
157 int dataSize = pkt->getSize();
158 numCycles += dataSize/width;
159 if (dataSize % width)
160 numCycles++;
161 }
162
163 // The first word will be delivered after the current tick, the delivery
164 // of the address if any, and one bus cycle to deliver the data
165 pkt->firstWordTime = headerTime + clock;
166
167 pkt->finishTime = headerTime + numCycles * clock;
168
169 return headerTime;
170 }
171
172 void Bus::occupyBus(Tick until)
173 {
174 if (until == 0) {
175 // shortcut for express snoop packets
176 return;
177 }
178
179 tickNextIdle = until;
180 reschedule(busIdleEvent, tickNextIdle, true);
181
182 DPRINTF(Bus, "The bus is now occupied from tick %d to %d\n",
183 curTick(), tickNextIdle);
184 }
185
186 bool
187 Bus::isOccupied(PacketPtr pkt, Port* port)
188 {
189 // first we see if the next idle tick is in the future, next the
190 // bus is considered occupied if there are ports on the retry list
191 // and we are not in a retry with the current port
192 if (tickNextIdle > curTick() ||
193 (!retryList.empty() && !(inRetry && port == retryList.front()))) {
194 addToRetryList(port);
195 return true;
196 }
197 return false;
198 }
199
200 bool
201 Bus::recvTimingReq(PacketPtr pkt)
202 {
203 // determine the source port based on the id
204 SlavePort *src_port = slavePorts[pkt->getSrc()];
205
206 // test if the bus should be considered occupied for the current
207 // packet, and exclude express snoops from the check
208 if (!pkt->isExpressSnoop() && isOccupied(pkt, src_port)) {
209 DPRINTF(Bus, "recvTimingReq: src %s %s 0x%x BUSY\n",
210 src_port->name(), pkt->cmdString(), pkt->getAddr());
211 return false;
212 }
213
214 DPRINTF(Bus, "recvTimingReq: src %s %s 0x%x\n",
215 src_port->name(), pkt->cmdString(), pkt->getAddr());
216
217 Tick headerFinishTime = pkt->isExpressSnoop() ? 0 : calcPacketTiming(pkt);
218 Tick packetFinishTime = pkt->isExpressSnoop() ? 0 : pkt->finishTime;
219
220 // uncacheable requests need never be snooped
221 if (!pkt->req->isUncacheable()) {
222 // the packet is a memory-mapped request and should be
223 // broadcasted to our snoopers but the source
224 forwardTiming(pkt, pkt->getSrc());
225 }
226
227 // remember if we add an outstanding req so we can undo it if
228 // necessary, if the packet needs a response, we should add it
229 // as outstanding and express snoops never fail so there is
230 // not need to worry about them
231 bool add_outstanding = !pkt->isExpressSnoop() && pkt->needsResponse();
232
233 // keep track that we have an outstanding request packet
234 // matching this request, this is used by the coherency
235 // mechanism in determining what to do with snoop responses
236 // (in recvTimingSnoop)
237 if (add_outstanding) {
238 // we should never have an exsiting request outstanding
239 assert(outstandingReq.find(pkt->req) == outstandingReq.end());
240 outstandingReq.insert(pkt->req);
241 }
242
243 // since it is a normal request, determine the destination
244 // based on the address and attempt to send the packet
245 bool success = masterPorts[findPort(pkt->getAddr())]->sendTimingReq(pkt);
246
247 if (!success) {
248 // inhibited packets should never be forced to retry
249 assert(!pkt->memInhibitAsserted());
250
251 // if it was added as outstanding and the send failed, then
252 // erase it again
253 if (add_outstanding)
254 outstandingReq.erase(pkt->req);
255
256 DPRINTF(Bus, "recvTimingReq: src %s %s 0x%x RETRY\n",
257 src_port->name(), pkt->cmdString(), pkt->getAddr());
258
259 addToRetryList(src_port);
260 occupyBus(headerFinishTime);
261
262 return false;
263 }
264
265 succeededTiming(packetFinishTime);
266
267 return true;
268 }
269
270 bool
271 Bus::recvTimingResp(PacketPtr pkt)
272 {
273 // determine the source port based on the id
274 MasterPort *src_port = masterPorts[pkt->getSrc()];
275
276 // test if the bus should be considered occupied for the current
277 // packet
278 if (isOccupied(pkt, src_port)) {
279 DPRINTF(Bus, "recvTimingResp: src %s %s 0x%x BUSY\n",
280 src_port->name(), pkt->cmdString(), pkt->getAddr());
281 return false;
282 }
283
284 DPRINTF(Bus, "recvTimingResp: src %s %s 0x%x\n",
285 src_port->name(), pkt->cmdString(), pkt->getAddr());
286
287 calcPacketTiming(pkt);
288 Tick packetFinishTime = pkt->finishTime;
289
290 // the packet is a normal response to a request that we should
291 // have seen passing through the bus
292 assert(outstandingReq.find(pkt->req) != outstandingReq.end());
293
294 // remove it as outstanding
295 outstandingReq.erase(pkt->req);
296
297 // send the packet to the destination through one of our slave
298 // ports, as determined by the destination field
299 bool success M5_VAR_USED = slavePorts[pkt->getDest()]->sendTimingResp(pkt);
300
301 // currently it is illegal to block responses... can lead to
302 // deadlock
303 assert(success);
304
305 succeededTiming(packetFinishTime);
306
307 return true;
308 }
309
310 void
311 Bus::recvTimingSnoopReq(PacketPtr pkt)
312 {
313 DPRINTF(Bus, "recvTimingSnoopReq: src %s %s 0x%x\n",
314 masterPorts[pkt->getSrc()]->name(), pkt->cmdString(),
315 pkt->getAddr());
316
317 // we should only see express snoops from caches
318 assert(pkt->isExpressSnoop());
319
320 // forward to all snoopers
321 forwardTiming(pkt, InvalidPortID);
322
323 // a snoop request came from a connected slave device (one of
324 // our master ports), and if it is not coming from the slave
325 // device responsible for the address range something is
326 // wrong, hence there is nothing further to do as the packet
327 // would be going back to where it came from
328 assert(pkt->getSrc() == findPort(pkt->getAddr()));
329
330 // this is an express snoop and is never forced to retry
331 assert(!inRetry);
332 }
333
334 bool
335 Bus::recvTimingSnoopResp(PacketPtr pkt)
336 {
337 // determine the source port based on the id
338 SlavePort* src_port = slavePorts[pkt->getSrc()];
339
340 if (isOccupied(pkt, src_port)) {
341 DPRINTF(Bus, "recvTimingSnoopResp: src %s %s 0x%x BUSY\n",
342 src_port->name(), pkt->cmdString(), pkt->getAddr());
343 return false;
344 }
345
346 DPRINTF(Bus, "recvTimingSnoop: src %s %s 0x%x\n",
347 src_port->name(), pkt->cmdString(), pkt->getAddr());
348
349 // get the destination from the packet
350 PortID dest = pkt->getDest();
351
352 // responses are never express snoops
353 assert(!pkt->isExpressSnoop());
354
355 calcPacketTiming(pkt);
356 Tick packetFinishTime = pkt->finishTime;
357
358 // determine if the response is from a snoop request we
359 // created as the result of a normal request (in which case it
360 // should be in the outstandingReq), or if we merely forwarded
361 // someone else's snoop request
362 if (outstandingReq.find(pkt->req) == outstandingReq.end()) {
363 // this is a snoop response to a snoop request we
364 // forwarded, e.g. coming from the L1 and going to the L2
365 // this should be forwarded as a snoop response
366 bool success M5_VAR_USED = masterPorts[dest]->sendTimingSnoopResp(pkt);
367 assert(success);
368 } else {
369 // we got a snoop response on one of our slave ports,
370 // i.e. from a coherent master connected to the bus, and
371 // since we created the snoop request as part of
372 // recvTiming, this should now be a normal response again
373 outstandingReq.erase(pkt->req);
374
375 // this is a snoop response from a coherent master, with a
376 // destination field set on its way through the bus as
377 // request, hence it should never go back to where the
378 // snoop response came from, but instead to where the
379 // original request came from
380 assert(pkt->getSrc() != dest);
381
382 // as a normal response, it should go back to a master
383 // through one of our slave ports
384 bool success M5_VAR_USED = slavePorts[dest]->sendTimingResp(pkt);
385
386 // currently it is illegal to block responses... can lead
387 // to deadlock
388 assert(success);
389 }
390
391 succeededTiming(packetFinishTime);
392
393 return true;
394 }
395
396
397 void
398 Bus::succeededTiming(Tick busy_time)
399 {
400 // occupy the bus accordingly
401 occupyBus(busy_time);
402
403 // if a retrying port succeeded, also take it off the retry list
404 if (inRetry) {
405 DPRINTF(Bus, "Remove retry from list %s\n",
406 retryList.front()->name());
407 retryList.pop_front();
408 inRetry = false;
409 }
410 }
411
412 void
413 Bus::forwardTiming(PacketPtr pkt, PortID exclude_slave_port_id)
414 {
415 for (SlavePortIter s = snoopPorts.begin(); s != snoopPorts.end(); ++s) {
416 SlavePort *p = *s;
417 // we could have gotten this request from a snooping master
418 // (corresponding to our own slave port that is also in
419 // snoopPorts) and should not send it back to where it came
420 // from
421 if (exclude_slave_port_id == InvalidPortID ||
422 p->getId() != exclude_slave_port_id) {
423 // cache is not allowed to refuse snoop
424 p->sendTimingSnoopReq(pkt);
425 }
426 }
427 }
428
429 void
430 Bus::releaseBus()
431 {
432 // releasing the bus means we should now be idle
433 assert(curTick() >= tickNextIdle);
434
435 // bus is now idle, so if someone is waiting we can retry
436 if (!retryList.empty()) {
437 // note that we block (return false on recvTiming) both
438 // because the bus is busy and because the destination is
439 // busy, and in the latter case the bus may be released before
440 // we see a retry from the destination
441 retryWaiting();
442 }
443
444 //If we weren't able to drain before, we might be able to now.
445 if (drainEvent && retryList.empty() && curTick() >= tickNextIdle) {
446 drainEvent->process();
447 // Clear the drain event once we're done with it.
448 drainEvent = NULL;
449 }
450 }
451
452 void
453 Bus::retryWaiting()
454 {
455 // this should never be called with an empty retry list
456 assert(!retryList.empty());
457
458 // send a retry to the port at the head of the retry list
459 inRetry = true;
460
461 // note that we might have blocked on the receiving port being
462 // busy (rather than the bus itself) and now call retry before the
463 // destination called retry on the bus
464 retryList.front()->sendRetry();
465
466 // If inRetry is still true, sendTiming wasn't called in zero time
467 // (e.g. the cache does this)
468 if (inRetry) {
469 retryList.pop_front();
470 inRetry = false;
471
472 //Bring tickNextIdle up to the present
473 while (tickNextIdle < curTick())
474 tickNextIdle += clock;
475
476 //Burn a cycle for the missed grant.
477 tickNextIdle += clock;
478
479 reschedule(busIdleEvent, tickNextIdle, true);
480 }
481 }
482
483 void
484 Bus::recvRetry(PortID id)
485 {
486 // we got a retry from a peer that we tried to send something to
487 // and failed, but we sent it on the account of someone else, and
488 // that source port should be on our retry list, however if the
489 // bus is released before this happens and the retry (from the bus
490 // point of view) is successful then this no longer holds and we
491 // could in fact have an empty retry list
492 if (retryList.empty())
493 return;
494
495 // if the bus isn't busy
496 if (curTick() >= tickNextIdle) {
497 // note that we do not care who told us to retry at the moment, we
498 // merely let the first one on the retry list go
499 retryWaiting();
500 }
501 }
502
503 PortID
504 Bus::findPort(Addr addr)
505 {
506 /* An interval tree would be a better way to do this. --ali. */
507 PortID dest_id = checkPortCache(addr);
508 if (dest_id != InvalidPortID)
509 return dest_id;
510
511 // Check normal port ranges
512 PortIter i = portMap.find(RangeSize(addr,1));
513 if (i != portMap.end()) {
514 dest_id = i->second;
515 updatePortCache(dest_id, i->first.start, i->first.end);
516 return dest_id;
517 }
518
519 // Check if this matches the default range
520 if (useDefaultRange) {
521 AddrRangeIter a_end = defaultRange.end();
522 for (AddrRangeIter i = defaultRange.begin(); i != a_end; i++) {
523 if (*i == addr) {
524 DPRINTF(Bus, " found addr %#llx on default\n", addr);
525 return defaultPortID;
526 }
527 }
528 } else if (defaultPortID != InvalidPortID) {
529 DPRINTF(Bus, "Unable to find destination for addr %#llx, "
530 "will use default port\n", addr);
531 return defaultPortID;
532 }
533
534 // we should use the range for the default port and it did not
535 // match, or the default port is not set
536 fatal("Unable to find destination for addr %#llx on bus %s\n", addr,
537 name());
538 }
539
540 Tick
541 Bus::recvAtomic(PacketPtr pkt)
542 {
543 DPRINTF(Bus, "recvAtomic: packet src %s addr 0x%x cmd %s\n",
544 slavePorts[pkt->getSrc()]->name(), pkt->getAddr(),
545 pkt->cmdString());
546
547 MemCmd snoop_response_cmd = MemCmd::InvalidCmd;
548 Tick snoop_response_latency = 0;
549
550 // uncacheable requests need never be snooped
551 if (!pkt->req->isUncacheable()) {
552 // forward to all snoopers but the source
553 std::pair<MemCmd, Tick> snoop_result =
554 forwardAtomic(pkt, pkt->getSrc());
555 snoop_response_cmd = snoop_result.first;
556 snoop_response_latency = snoop_result.second;
557 }
558
559 // even if we had a snoop response, we must continue and also
560 // perform the actual request at the destination
561 PortID dest_id = findPort(pkt->getAddr());
562
563 // forward the request to the appropriate destination
564 Tick response_latency = masterPorts[dest_id]->sendAtomic(pkt);
565
566 // if we got a response from a snooper, restore it here
567 if (snoop_response_cmd != MemCmd::InvalidCmd) {
568 // no one else should have responded
569 assert(!pkt->isResponse());
570 pkt->cmd = snoop_response_cmd;
571 response_latency = snoop_response_latency;
572 }
573
574 pkt->finishTime = curTick() + response_latency;
575 return response_latency;
576 }
577
578 Tick
579 Bus::recvAtomicSnoop(PacketPtr pkt)
580 {
581 DPRINTF(Bus, "recvAtomicSnoop: packet src %s addr 0x%x cmd %s\n",
582 masterPorts[pkt->getSrc()]->name(), pkt->getAddr(),
583 pkt->cmdString());
584
585 // forward to all snoopers
586 std::pair<MemCmd, Tick> snoop_result =
587 forwardAtomic(pkt, InvalidPortID);
588 MemCmd snoop_response_cmd = snoop_result.first;
589 Tick snoop_response_latency = snoop_result.second;
590
591 if (snoop_response_cmd != MemCmd::InvalidCmd)
592 pkt->cmd = snoop_response_cmd;
593
594 pkt->finishTime = curTick() + snoop_response_latency;
595 return snoop_response_latency;
596 }
597
598 std::pair<MemCmd, Tick>
599 Bus::forwardAtomic(PacketPtr pkt, PortID exclude_slave_port_id)
600 {
601 // the packet may be changed on snoops, record the original source
602 // and command to enable us to restore it between snoops so that
603 // additional snoops can take place properly
604 PortID orig_src_id = pkt->getSrc();
605 MemCmd orig_cmd = pkt->cmd;
606 MemCmd snoop_response_cmd = MemCmd::InvalidCmd;
607 Tick snoop_response_latency = 0;
608
609 for (SlavePortIter s = snoopPorts.begin(); s != snoopPorts.end(); ++s) {
610 SlavePort *p = *s;
611 // we could have gotten this request from a snooping master
612 // (corresponding to our own slave port that is also in
613 // snoopPorts) and should not send it back to where it came
614 // from
615 if (exclude_slave_port_id == InvalidPortID ||
616 p->getId() != exclude_slave_port_id) {
617 Tick latency = p->sendAtomicSnoop(pkt);
618 // in contrast to a functional access, we have to keep on
619 // going as all snoopers must be updated even if we get a
620 // response
621 if (pkt->isResponse()) {
622 // response from snoop agent
623 assert(pkt->cmd != orig_cmd);
624 assert(pkt->memInhibitAsserted());
625 // should only happen once
626 assert(snoop_response_cmd == MemCmd::InvalidCmd);
627 // save response state
628 snoop_response_cmd = pkt->cmd;
629 snoop_response_latency = latency;
630 // restore original packet state for remaining snoopers
631 pkt->cmd = orig_cmd;
632 pkt->setSrc(orig_src_id);
633 pkt->clearDest();
634 }
635 }
636 }
637
638 // the packet is restored as part of the loop and any potential
639 // snoop response is part of the returned pair
640 return std::make_pair(snoop_response_cmd, snoop_response_latency);
641 }
642
643 void
644 Bus::recvFunctional(PacketPtr pkt)
645 {
646 if (!pkt->isPrint()) {
647 // don't do DPRINTFs on PrintReq as it clutters up the output
648 DPRINTF(Bus,
649 "recvFunctional: packet src %s addr 0x%x cmd %s\n",
650 slavePorts[pkt->getSrc()]->name(), pkt->getAddr(),
651 pkt->cmdString());
652 }
653
654 // uncacheable requests need never be snooped
655 if (!pkt->req->isUncacheable()) {
656 // forward to all snoopers but the source
657 forwardFunctional(pkt, pkt->getSrc());
658 }
659
660 // there is no need to continue if the snooping has found what we
661 // were looking for and the packet is already a response
662 if (!pkt->isResponse()) {
663 PortID dest_id = findPort(pkt->getAddr());
664
665 masterPorts[dest_id]->sendFunctional(pkt);
666 }
667 }
668
669 void
670 Bus::recvFunctionalSnoop(PacketPtr pkt)
671 {
672 if (!pkt->isPrint()) {
673 // don't do DPRINTFs on PrintReq as it clutters up the output
674 DPRINTF(Bus,
675 "recvFunctionalSnoop: packet src %s addr 0x%x cmd %s\n",
676 masterPorts[pkt->getSrc()]->name(), pkt->getAddr(),
677 pkt->cmdString());
678 }
679
680 // forward to all snoopers
681 forwardFunctional(pkt, InvalidPortID);
682 }
683
684 void
685 Bus::forwardFunctional(PacketPtr pkt, PortID exclude_slave_port_id)
686 {
687 for (SlavePortIter s = snoopPorts.begin(); s != snoopPorts.end(); ++s) {
688 SlavePort *p = *s;
689 // we could have gotten this request from a snooping master
690 // (corresponding to our own slave port that is also in
691 // snoopPorts) and should not send it back to where it came
692 // from
693 if (exclude_slave_port_id == InvalidPortID ||
694 p->getId() != exclude_slave_port_id)
695 p->sendFunctionalSnoop(pkt);
696
697 // if we get a response we are done
698 if (pkt->isResponse()) {
699 break;
700 }
701 }
702 }
703
704 /** Function called by the port when the bus is receiving a range change.*/
705 void
706 Bus::recvRangeChange(PortID id)
707 {
708 AddrRangeList ranges;
709 AddrRangeIter iter;
710
711 if (inRecvRangeChange.count(id))
712 return;
713 inRecvRangeChange.insert(id);
714
715 DPRINTF(BusAddrRanges, "received RangeChange from device id %d\n", id);
716
717 clearPortCache();
718 if (id == defaultPortID) {
719 defaultRange.clear();
720 // Only try to update these ranges if the user set a default responder.
721 if (useDefaultRange) {
722 AddrRangeList ranges =
723 masterPorts[id]->getSlavePort().getAddrRanges();
724 for(iter = ranges.begin(); iter != ranges.end(); iter++) {
725 defaultRange.push_back(*iter);
726 DPRINTF(BusAddrRanges, "Adding range %#llx - %#llx for default range\n",
727 iter->start, iter->end);
728 }
729 }
730 } else {
731
732 assert(id < masterPorts.size() && id >= 0);
733 MasterPort *port = masterPorts[id];
734
735 // Clean out any previously existent ids
736 for (PortIter portIter = portMap.begin();
737 portIter != portMap.end(); ) {
738 if (portIter->second == id)
739 portMap.erase(portIter++);
740 else
741 portIter++;
742 }
743
744 ranges = port->getSlavePort().getAddrRanges();
745
746 for (iter = ranges.begin(); iter != ranges.end(); iter++) {
747 DPRINTF(BusAddrRanges, "Adding range %#llx - %#llx for id %d\n",
748 iter->start, iter->end, id);
749 if (portMap.insert(*iter, id) == portMap.end()) {
750 PortID conflict_id = portMap.find(*iter)->second;
751 fatal("%s has two ports with same range:\n\t%s\n\t%s\n",
752 name(), masterPorts[id]->getSlavePort().name(),
753 masterPorts[conflict_id]->getSlavePort().name());
754 }
755 }
756 }
757 DPRINTF(BusAddrRanges, "port list has %d entries\n", portMap.size());
758
759 // tell all our neighbouring master ports that our address range
760 // has changed
761 for (SlavePortConstIter p = slavePorts.begin(); p != slavePorts.end();
762 ++p)
763 (*p)->sendRangeChange();
764
765 inRecvRangeChange.erase(id);
766 }
767
768 AddrRangeList
769 Bus::getAddrRanges(PortID id)
770 {
771 AddrRangeList ranges;
772
773 DPRINTF(BusAddrRanges, "received address range request, returning:\n");
774
775 for (AddrRangeIter dflt_iter = defaultRange.begin();
776 dflt_iter != defaultRange.end(); dflt_iter++) {
777 ranges.push_back(*dflt_iter);
778 DPRINTF(BusAddrRanges, " -- Dflt: %#llx : %#llx\n",dflt_iter->start,
779 dflt_iter->end);
780 }
781 for (PortIter portIter = portMap.begin();
782 portIter != portMap.end(); portIter++) {
783 bool subset = false;
784 for (AddrRangeIter dflt_iter = defaultRange.begin();
785 dflt_iter != defaultRange.end(); dflt_iter++) {
786 if ((portIter->first.start < dflt_iter->start &&
787 portIter->first.end >= dflt_iter->start) ||
788 (portIter->first.start < dflt_iter->end &&
789 portIter->first.end >= dflt_iter->end))
790 fatal("Devices can not set ranges that itersect the default set\
791 but are not a subset of the default set.\n");
792 if (portIter->first.start >= dflt_iter->start &&
793 portIter->first.end <= dflt_iter->end) {
794 subset = true;
795 DPRINTF(BusAddrRanges, " -- %#llx : %#llx is a SUBSET\n",
796 portIter->first.start, portIter->first.end);
797 }
798 }
799 if (portIter->second != id && !subset) {
800 ranges.push_back(portIter->first);
801 DPRINTF(BusAddrRanges, " -- %#llx : %#llx\n",
802 portIter->first.start, portIter->first.end);
803 }
804 }
805
806 return ranges;
807 }
808
809 bool
810 Bus::isSnooping(PortID id) const
811 {
812 // in essence, answer the question if there are snooping ports
813 return !snoopPorts.empty();
814 }
815
816 unsigned
817 Bus::findBlockSize(PortID id)
818 {
819 if (cachedBlockSizeValid)
820 return cachedBlockSize;
821
822 unsigned max_bs = 0;
823
824 PortIter p_end = portMap.end();
825 for (PortIter p_iter = portMap.begin(); p_iter != p_end; p_iter++) {
826 unsigned tmp_bs = masterPorts[p_iter->second]->peerBlockSize();
827 if (tmp_bs > max_bs)
828 max_bs = tmp_bs;
829 }
830
831 for (SlavePortConstIter s = snoopPorts.begin(); s != snoopPorts.end();
832 ++s) {
833 unsigned tmp_bs = (*s)->peerBlockSize();
834 if (tmp_bs > max_bs)
835 max_bs = tmp_bs;
836 }
837 if (max_bs == 0)
838 max_bs = defaultBlockSize;
839
840 if (max_bs != 64)
841 warn_once("Blocksize found to not be 64... hmm... probably not.\n");
842 cachedBlockSize = max_bs;
843 cachedBlockSizeValid = true;
844 return max_bs;
845 }
846
847
848 unsigned int
849 Bus::drain(Event * de)
850 {
851 //We should check that we're not "doing" anything, and that noone is
852 //waiting. We might be idle but have someone waiting if the device we
853 //contacted for a retry didn't actually retry.
854 if (!retryList.empty() || (curTick() < tickNextIdle &&
855 busIdleEvent.scheduled())) {
856 drainEvent = de;
857 return 1;
858 }
859 return 0;
860 }
861
862 void
863 Bus::startup()
864 {
865 if (tickNextIdle < curTick())
866 tickNextIdle = (curTick() / clock) * clock + clock;
867 }
868
869 Bus *
870 BusParams::create()
871 {
872 return new Bus(this);
873 }