Replace curTick global variable with accessor functions.
[gem5.git] / src / mem / bus.cc
1 /*
2 * Copyright (c) 2006 The Regents of The University of Michigan
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 * Authors: Ali Saidi
29 */
30
31 /**
32 * @file
33 * Definition of a bus object.
34 */
35
36 #include <algorithm>
37 #include <limits>
38
39 #include "base/misc.hh"
40 #include "base/trace.hh"
41 #include "mem/bus.hh"
42
43 Bus::Bus(const BusParams *p)
44 : MemObject(p), busId(p->bus_id), clock(p->clock),
45 headerCycles(p->header_cycles), width(p->width), tickNextIdle(0),
46 drainEvent(NULL), busIdle(this), inRetry(false), maxId(0),
47 defaultPort(NULL), funcPort(NULL), funcPortId(-4),
48 useDefaultRange(p->use_default_range), defaultBlockSize(p->block_size),
49 cachedBlockSize(0), cachedBlockSizeValid(false)
50 {
51 //width, clock period, and header cycles must be positive
52 if (width <= 0)
53 fatal("Bus width must be positive\n");
54 if (clock <= 0)
55 fatal("Bus clock period must be positive\n");
56 if (headerCycles <= 0)
57 fatal("Number of header cycles must be positive\n");
58 clearBusCache();
59 clearPortCache();
60 }
61
62 Port *
63 Bus::getPort(const std::string &if_name, int idx)
64 {
65 if (if_name == "default") {
66 if (defaultPort == NULL) {
67 defaultPort = new BusPort(csprintf("%s-default",name()), this,
68 defaultId);
69 cachedBlockSizeValid = false;
70 return defaultPort;
71 } else
72 fatal("Default port already set\n");
73 }
74 int id;
75 if (if_name == "functional") {
76 if (!funcPort) {
77 id = maxId++;
78 funcPort = new BusPort(csprintf("%s-p%d-func", name(), id), this, id);
79 funcPortId = id;
80 interfaces[id] = funcPort;
81 }
82 return funcPort;
83 }
84
85 // if_name ignored? forced to be empty?
86 id = maxId++;
87 assert(maxId < std::numeric_limits<typeof(maxId)>::max());
88 BusPort *bp = new BusPort(csprintf("%s-p%d", name(), id), this, id);
89 interfaces[id] = bp;
90 cachedBlockSizeValid = false;
91 return bp;
92 }
93
94 void
95 Bus::deletePortRefs(Port *p)
96 {
97
98 BusPort *bp = dynamic_cast<BusPort*>(p);
99 if (bp == NULL)
100 panic("Couldn't convert Port* to BusPort*\n");
101 // If this is our one functional port
102 if (funcPort == bp)
103 return;
104 interfaces.erase(bp->getId());
105 clearBusCache();
106 delete bp;
107 }
108
109 /** Get the ranges of anyone other buses that we are connected to. */
110 void
111 Bus::init()
112 {
113 m5::hash_map<short,BusPort*>::iterator intIter;
114
115 for (intIter = interfaces.begin(); intIter != interfaces.end(); intIter++)
116 intIter->second->sendStatusChange(Port::RangeChange);
117 }
118
119 Bus::BusFreeEvent::BusFreeEvent(Bus *_bus)
120 : bus(_bus)
121 {}
122
123 void
124 Bus::BusFreeEvent::process()
125 {
126 bus->recvRetry(-1);
127 }
128
129 const char *
130 Bus::BusFreeEvent::description() const
131 {
132 return "bus became available";
133 }
134
135 Tick
136 Bus::calcPacketTiming(PacketPtr pkt)
137 {
138 // Bring tickNextIdle up to the present tick.
139 // There is some potential ambiguity where a cycle starts, which
140 // might make a difference when devices are acting right around a
141 // cycle boundary. Using a < allows things which happen exactly on
142 // a cycle boundary to take up only the following cycle. Anything
143 // that happens later will have to "wait" for the end of that
144 // cycle, and then start using the bus after that.
145 if (tickNextIdle < curTick()) {
146 tickNextIdle = curTick();
147 if (tickNextIdle % clock != 0)
148 tickNextIdle = curTick() - (curTick() % clock) + clock;
149 }
150
151 Tick headerTime = tickNextIdle + headerCycles * clock;
152
153 // The packet will be sent. Figure out how long it occupies the bus, and
154 // how much of that time is for the first "word", aka bus width.
155 int numCycles = 0;
156 if (pkt->hasData()) {
157 // If a packet has data, it needs ceil(size/width) cycles to send it
158 int dataSize = pkt->getSize();
159 numCycles += dataSize/width;
160 if (dataSize % width)
161 numCycles++;
162 }
163
164 // The first word will be delivered after the current tick, the delivery
165 // of the address if any, and one bus cycle to deliver the data
166 pkt->firstWordTime = headerTime + clock;
167
168 pkt->finishTime = headerTime + numCycles * clock;
169
170 return headerTime;
171 }
172
173 void Bus::occupyBus(Tick until)
174 {
175 if (until == 0) {
176 // shortcut for express snoop packets
177 return;
178 }
179
180 tickNextIdle = until;
181 reschedule(busIdle, tickNextIdle, true);
182
183 DPRINTF(Bus, "The bus is now occupied from tick %d to %d\n",
184 curTick(), tickNextIdle);
185 }
186
187 /** Function called by the port when the bus is receiving a Timing
188 * transaction.*/
189 bool
190 Bus::recvTiming(PacketPtr pkt)
191 {
192 short src = pkt->getSrc();
193
194 BusPort *src_port;
195 if (src == defaultId)
196 src_port = defaultPort;
197 else {
198 src_port = checkBusCache(src);
199 if (src_port == NULL) {
200 src_port = interfaces[src];
201 updateBusCache(src, src_port);
202 }
203 }
204
205 // If the bus is busy, or other devices are in line ahead of the current
206 // one, put this device on the retry list.
207 if (!pkt->isExpressSnoop() &&
208 (tickNextIdle > curTick() ||
209 (retryList.size() && (!inRetry || src_port != retryList.front()))))
210 {
211 addToRetryList(src_port);
212 DPRINTF(Bus, "recvTiming: src %d dst %d %s 0x%x BUSY\n",
213 src, pkt->getDest(), pkt->cmdString(), pkt->getAddr());
214 return false;
215 }
216
217 DPRINTF(Bus, "recvTiming: src %d dst %d %s 0x%x\n",
218 src, pkt->getDest(), pkt->cmdString(), pkt->getAddr());
219
220 Tick headerFinishTime = pkt->isExpressSnoop() ? 0 : calcPacketTiming(pkt);
221 Tick packetFinishTime = pkt->isExpressSnoop() ? 0 : pkt->finishTime;
222
223 short dest = pkt->getDest();
224 int dest_port_id;
225 Port *dest_port;
226
227 if (dest == Packet::Broadcast) {
228 dest_port_id = findPort(pkt->getAddr());
229 dest_port = (dest_port_id == defaultId) ?
230 defaultPort : interfaces[dest_port_id];
231 SnoopIter s_end = snoopPorts.end();
232 for (SnoopIter s_iter = snoopPorts.begin(); s_iter != s_end; s_iter++) {
233 BusPort *p = *s_iter;
234 if (p != dest_port && p != src_port) {
235 // cache is not allowed to refuse snoop
236 bool success M5_VAR_USED = p->sendTiming(pkt);
237 assert(success);
238 }
239 }
240 } else {
241 assert(dest < maxId);
242 assert(dest != src); // catch infinite loops
243 dest_port_id = dest;
244 if (dest_port_id == defaultId)
245 dest_port = defaultPort;
246 else {
247 dest_port = checkBusCache(dest);
248 if (dest_port == NULL) {
249 dest_port = interfaces[dest_port_id];
250 // updateBusCache(dest_port_id, dest_port);
251 }
252 }
253 dest_port = (dest_port_id == defaultId) ?
254 defaultPort : interfaces[dest_port_id];
255 }
256
257 if (dest_port_id == src) {
258 // Must be forwarded snoop up from below...
259 assert(dest == Packet::Broadcast);
260 } else {
261 // send to actual target
262 if (!dest_port->sendTiming(pkt)) {
263 // Packet not successfully sent. Leave or put it on the retry list.
264 // illegal to block responses... can lead to deadlock
265 assert(!pkt->isResponse());
266 // It's also illegal to force a transaction to retry after
267 // someone else has committed to respond.
268 assert(!pkt->memInhibitAsserted());
269 DPRINTF(Bus, "recvTiming: src %d dst %d %s 0x%x TGT RETRY\n",
270 src, pkt->getDest(), pkt->cmdString(), pkt->getAddr());
271 addToRetryList(src_port);
272 occupyBus(headerFinishTime);
273 return false;
274 }
275 // send OK, fall through... pkt may have been deleted by
276 // target at this point, so it should *not* be referenced
277 // again. We'll set it to NULL here just to be safe.
278 pkt = NULL;
279 }
280
281 occupyBus(packetFinishTime);
282
283 // Packet was successfully sent.
284 // Also take care of retries
285 if (inRetry) {
286 DPRINTF(Bus, "Remove retry from list %d\n", src);
287 retryList.front()->onRetryList(false);
288 retryList.pop_front();
289 inRetry = false;
290 }
291 return true;
292 }
293
294 void
295 Bus::recvRetry(int id)
296 {
297 // If there's anything waiting, and the bus isn't busy...
298 if (retryList.size() && curTick() >= tickNextIdle) {
299 //retryingPort = retryList.front();
300 inRetry = true;
301 DPRINTF(Bus, "Sending a retry to %s\n", retryList.front()->getPeer()->name());
302 retryList.front()->sendRetry();
303 // If inRetry is still true, sendTiming wasn't called
304 if (inRetry)
305 {
306 retryList.front()->onRetryList(false);
307 retryList.pop_front();
308 inRetry = false;
309
310 //Bring tickNextIdle up to the present
311 while (tickNextIdle < curTick())
312 tickNextIdle += clock;
313
314 //Burn a cycle for the missed grant.
315 tickNextIdle += clock;
316
317 reschedule(busIdle, tickNextIdle, true);
318 }
319 }
320 //If we weren't able to drain before, we might be able to now.
321 if (drainEvent && retryList.size() == 0 && curTick() >= tickNextIdle) {
322 drainEvent->process();
323 // Clear the drain event once we're done with it.
324 drainEvent = NULL;
325 }
326 }
327
328 int
329 Bus::findPort(Addr addr)
330 {
331 /* An interval tree would be a better way to do this. --ali. */
332 int dest_id;
333
334 dest_id = checkPortCache(addr);
335 if (dest_id != -1)
336 return dest_id;
337
338 // Check normal port ranges
339 PortIter i = portMap.find(RangeSize(addr,1));
340 if (i != portMap.end()) {
341 dest_id = i->second;
342 updatePortCache(dest_id, i->first.start, i->first.end);
343 return dest_id;
344 }
345
346 // Check if this matches the default range
347 if (useDefaultRange) {
348 AddrRangeIter a_end = defaultRange.end();
349 for (AddrRangeIter i = defaultRange.begin(); i != a_end; i++) {
350 if (*i == addr) {
351 DPRINTF(Bus, " found addr %#llx on default\n", addr);
352 return defaultId;
353 }
354 }
355
356 panic("Unable to find destination for addr %#llx\n", addr);
357 }
358
359 DPRINTF(Bus, "Unable to find destination for addr %#llx, "
360 "will use default port\n", addr);
361 return defaultId;
362 }
363
364
365 /** Function called by the port when the bus is receiving a Atomic
366 * transaction.*/
367 Tick
368 Bus::recvAtomic(PacketPtr pkt)
369 {
370 DPRINTF(Bus, "recvAtomic: packet src %d dest %d addr 0x%x cmd %s\n",
371 pkt->getSrc(), pkt->getDest(), pkt->getAddr(), pkt->cmdString());
372 assert(pkt->getDest() == Packet::Broadcast);
373 assert(pkt->isRequest());
374
375 // Variables for recording original command and snoop response (if
376 // any)... if a snooper respondes, we will need to restore
377 // original command so that additional snoops can take place
378 // properly
379 MemCmd orig_cmd = pkt->cmd;
380 MemCmd snoop_response_cmd = MemCmd::InvalidCmd;
381 Tick snoop_response_latency = 0;
382 int orig_src = pkt->getSrc();
383
384 int target_port_id = findPort(pkt->getAddr());
385 BusPort *target_port;
386 if (target_port_id == defaultId)
387 target_port = defaultPort;
388 else {
389 target_port = checkBusCache(target_port_id);
390 if (target_port == NULL) {
391 target_port = interfaces[target_port_id];
392 updateBusCache(target_port_id, target_port);
393 }
394 }
395
396 SnoopIter s_end = snoopPorts.end();
397 for (SnoopIter s_iter = snoopPorts.begin(); s_iter != s_end; s_iter++) {
398 BusPort *p = *s_iter;
399 // same port should not have both target addresses and snooping
400 assert(p != target_port);
401 if (p->getId() != pkt->getSrc()) {
402 Tick latency = p->sendAtomic(pkt);
403 if (pkt->isResponse()) {
404 // response from snoop agent
405 assert(pkt->cmd != orig_cmd);
406 assert(pkt->memInhibitAsserted());
407 // should only happen once
408 assert(snoop_response_cmd == MemCmd::InvalidCmd);
409 // save response state
410 snoop_response_cmd = pkt->cmd;
411 snoop_response_latency = latency;
412 // restore original packet state for remaining snoopers
413 pkt->cmd = orig_cmd;
414 pkt->setSrc(orig_src);
415 pkt->setDest(Packet::Broadcast);
416 }
417 }
418 }
419
420 Tick response_latency = 0;
421
422 // we can get requests sent up from the memory side of the bus for
423 // snooping... don't send them back down!
424 if (target_port_id != pkt->getSrc()) {
425 response_latency = target_port->sendAtomic(pkt);
426 }
427
428 // if we got a response from a snooper, restore it here
429 if (snoop_response_cmd != MemCmd::InvalidCmd) {
430 // no one else should have responded
431 assert(!pkt->isResponse());
432 assert(pkt->cmd == orig_cmd);
433 pkt->cmd = snoop_response_cmd;
434 response_latency = snoop_response_latency;
435 }
436
437 // why do we have this packet field and the return value both???
438 pkt->finishTime = curTick() + response_latency;
439 return response_latency;
440 }
441
442 /** Function called by the port when the bus is receiving a Functional
443 * transaction.*/
444 void
445 Bus::recvFunctional(PacketPtr pkt)
446 {
447 if (!pkt->isPrint()) {
448 // don't do DPRINTFs on PrintReq as it clutters up the output
449 DPRINTF(Bus,
450 "recvFunctional: packet src %d dest %d addr 0x%x cmd %s\n",
451 pkt->getSrc(), pkt->getDest(), pkt->getAddr(),
452 pkt->cmdString());
453 }
454 assert(pkt->getDest() == Packet::Broadcast);
455
456 int port_id = findPort(pkt->getAddr());
457 Port *port = (port_id == defaultId) ? defaultPort : interfaces[port_id];
458 // The packet may be changed by another bus on snoops, restore the
459 // id after each
460 int src_id = pkt->getSrc();
461
462 assert(pkt->isRequest()); // hasn't already been satisfied
463
464 SnoopIter s_end = snoopPorts.end();
465 for (SnoopIter s_iter = snoopPorts.begin(); s_iter != s_end; s_iter++) {
466 BusPort *p = *s_iter;
467 if (p != port && p->getId() != src_id) {
468 p->sendFunctional(pkt);
469 }
470 if (pkt->isResponse()) {
471 break;
472 }
473 pkt->setSrc(src_id);
474 }
475
476 // If the snooping hasn't found what we were looking for, keep going.
477 if (!pkt->isResponse() && port_id != pkt->getSrc()) {
478 port->sendFunctional(pkt);
479 }
480 }
481
482 /** Function called by the port when the bus is receiving a status change.*/
483 void
484 Bus::recvStatusChange(Port::Status status, int id)
485 {
486 AddrRangeList ranges;
487 bool snoops;
488 AddrRangeIter iter;
489
490 if (inRecvStatusChange.count(id))
491 return;
492 inRecvStatusChange.insert(id);
493
494 assert(status == Port::RangeChange &&
495 "The other statuses need to be implemented.");
496
497 DPRINTF(BusAddrRanges, "received RangeChange from device id %d\n", id);
498
499 clearPortCache();
500 if (id == defaultId) {
501 defaultRange.clear();
502 // Only try to update these ranges if the user set a default responder.
503 if (useDefaultRange) {
504 defaultPort->getPeerAddressRanges(ranges, snoops);
505 assert(snoops == false);
506 for(iter = ranges.begin(); iter != ranges.end(); iter++) {
507 defaultRange.push_back(*iter);
508 DPRINTF(BusAddrRanges, "Adding range %#llx - %#llx for default range\n",
509 iter->start, iter->end);
510 }
511 }
512 } else {
513
514 assert((id < maxId && id >= 0) || id == defaultId);
515 BusPort *port = interfaces[id];
516
517 // Clean out any previously existent ids
518 for (PortIter portIter = portMap.begin();
519 portIter != portMap.end(); ) {
520 if (portIter->second == id)
521 portMap.erase(portIter++);
522 else
523 portIter++;
524 }
525
526 for (SnoopIter s_iter = snoopPorts.begin();
527 s_iter != snoopPorts.end(); ) {
528 if ((*s_iter)->getId() == id)
529 s_iter = snoopPorts.erase(s_iter);
530 else
531 s_iter++;
532 }
533
534 port->getPeerAddressRanges(ranges, snoops);
535
536 if (snoops) {
537 DPRINTF(BusAddrRanges, "Adding id %d to snoop list\n", id);
538 snoopPorts.push_back(port);
539 }
540
541 for (iter = ranges.begin(); iter != ranges.end(); iter++) {
542 DPRINTF(BusAddrRanges, "Adding range %#llx - %#llx for id %d\n",
543 iter->start, iter->end, id);
544 if (portMap.insert(*iter, id) == portMap.end()) {
545 int conflict_id = portMap.find(*iter)->second;
546 fatal("%s has two ports with same range:\n\t%s\n\t%s\n",
547 name(), interfaces[id]->getPeer()->name(),
548 interfaces[conflict_id]->getPeer()->name());
549 }
550 }
551 }
552 DPRINTF(MMU, "port list has %d entries\n", portMap.size());
553
554 // tell all our peers that our address range has changed.
555 // Don't tell the device that caused this change, it already knows
556 m5::hash_map<short,BusPort*>::iterator intIter;
557
558 for (intIter = interfaces.begin(); intIter != interfaces.end(); intIter++)
559 if (intIter->first != id && intIter->first != funcPortId)
560 intIter->second->sendStatusChange(Port::RangeChange);
561
562 if (id != defaultId && defaultPort)
563 defaultPort->sendStatusChange(Port::RangeChange);
564 inRecvStatusChange.erase(id);
565 }
566
567 void
568 Bus::addressRanges(AddrRangeList &resp, bool &snoop, int id)
569 {
570 resp.clear();
571 snoop = false;
572
573 DPRINTF(BusAddrRanges, "received address range request, returning:\n");
574
575 for (AddrRangeIter dflt_iter = defaultRange.begin();
576 dflt_iter != defaultRange.end(); dflt_iter++) {
577 resp.push_back(*dflt_iter);
578 DPRINTF(BusAddrRanges, " -- Dflt: %#llx : %#llx\n",dflt_iter->start,
579 dflt_iter->end);
580 }
581 for (PortIter portIter = portMap.begin();
582 portIter != portMap.end(); portIter++) {
583 bool subset = false;
584 for (AddrRangeIter dflt_iter = defaultRange.begin();
585 dflt_iter != defaultRange.end(); dflt_iter++) {
586 if ((portIter->first.start < dflt_iter->start &&
587 portIter->first.end >= dflt_iter->start) ||
588 (portIter->first.start < dflt_iter->end &&
589 portIter->first.end >= dflt_iter->end))
590 fatal("Devices can not set ranges that itersect the default set\
591 but are not a subset of the default set.\n");
592 if (portIter->first.start >= dflt_iter->start &&
593 portIter->first.end <= dflt_iter->end) {
594 subset = true;
595 DPRINTF(BusAddrRanges, " -- %#llx : %#llx is a SUBSET\n",
596 portIter->first.start, portIter->first.end);
597 }
598 }
599 if (portIter->second != id && !subset) {
600 resp.push_back(portIter->first);
601 DPRINTF(BusAddrRanges, " -- %#llx : %#llx\n",
602 portIter->first.start, portIter->first.end);
603 }
604 }
605
606 for (SnoopIter s_iter = snoopPorts.begin(); s_iter != snoopPorts.end();
607 s_iter++) {
608 if ((*s_iter)->getId() != id) {
609 snoop = true;
610 break;
611 }
612 }
613 }
614
615 unsigned
616 Bus::findBlockSize(int id)
617 {
618 if (cachedBlockSizeValid)
619 return cachedBlockSize;
620
621 unsigned max_bs = 0;
622
623 PortIter p_end = portMap.end();
624 for (PortIter p_iter = portMap.begin(); p_iter != p_end; p_iter++) {
625 unsigned tmp_bs = interfaces[p_iter->second]->peerBlockSize();
626 if (tmp_bs > max_bs)
627 max_bs = tmp_bs;
628 }
629 SnoopIter s_end = snoopPorts.end();
630 for (SnoopIter s_iter = snoopPorts.begin(); s_iter != s_end; s_iter++) {
631 unsigned tmp_bs = (*s_iter)->peerBlockSize();
632 if (tmp_bs > max_bs)
633 max_bs = tmp_bs;
634 }
635 if (max_bs == 0)
636 max_bs = defaultBlockSize;
637
638 if (max_bs != 64)
639 warn_once("Blocksize found to not be 64... hmm... probably not.\n");
640 cachedBlockSize = max_bs;
641 cachedBlockSizeValid = true;
642 return max_bs;
643 }
644
645
646 unsigned int
647 Bus::drain(Event * de)
648 {
649 //We should check that we're not "doing" anything, and that noone is
650 //waiting. We might be idle but have someone waiting if the device we
651 //contacted for a retry didn't actually retry.
652 if (retryList.size() || (curTick() < tickNextIdle && busIdle.scheduled())) {
653 drainEvent = de;
654 return 1;
655 }
656 return 0;
657 }
658
659 void
660 Bus::startup()
661 {
662 if (tickNextIdle < curTick())
663 tickNextIdle = (curTick() / clock) * clock + clock;
664 }
665
666 Bus *
667 BusParams::create()
668 {
669 return new Bus(this);
670 }