Merge ktlim@zizzer:/bk/newmem
[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
37 #include <limits>
38
39 #include "base/misc.hh"
40 #include "base/trace.hh"
41 #include "mem/bus.hh"
42 #include "sim/builder.hh"
43
44 Port *
45 Bus::getPort(const std::string &if_name, int idx)
46 {
47 if (if_name == "default") {
48 if (defaultPort == NULL) {
49 defaultPort = new BusPort(csprintf("%s-default",name()), this,
50 defaultId);
51 return defaultPort;
52 } else
53 fatal("Default port already set\n");
54 }
55
56 // if_name ignored? forced to be empty?
57 int id = maxId++;
58 assert(maxId < std::numeric_limits<typeof(maxId)>::max());
59 BusPort *bp = new BusPort(csprintf("%s-p%d", name(), id), this, id);
60 interfaces[id] = bp;
61 return bp;
62 }
63
64 void
65 Bus::deletePortRefs(Port *p)
66 {
67 BusPort *bp = dynamic_cast<BusPort*>(p);
68 if (bp == NULL)
69 panic("Couldn't convert Port* to BusPort*\n");
70 interfaces.erase(bp->getId());
71 }
72
73 /** Get the ranges of anyone other buses that we are connected to. */
74 void
75 Bus::init()
76 {
77 m5::hash_map<short,BusPort*>::iterator intIter;
78
79 for (intIter = interfaces.begin(); intIter != interfaces.end(); intIter++)
80 intIter->second->sendStatusChange(Port::RangeChange);
81 }
82
83 Bus::BusFreeEvent::BusFreeEvent(Bus *_bus) : Event(&mainEventQueue), bus(_bus)
84 {}
85
86 void Bus::BusFreeEvent::process()
87 {
88 bus->recvRetry(-1);
89 }
90
91 const char * Bus::BusFreeEvent::description()
92 {
93 return "bus became available";
94 }
95
96 void Bus::occupyBus(PacketPtr pkt)
97 {
98 //Bring tickNextIdle up to the present tick
99 //There is some potential ambiguity where a cycle starts, which might make
100 //a difference when devices are acting right around a cycle boundary. Using
101 //a < allows things which happen exactly on a cycle boundary to take up only
102 //the following cycle. Anthing that happens later will have to "wait" for
103 //the end of that cycle, and then start using the bus after that.
104 while (tickNextIdle < curTick)
105 tickNextIdle += clock;
106
107 // The packet will be sent. Figure out how long it occupies the bus, and
108 // how much of that time is for the first "word", aka bus width.
109 int numCycles = 0;
110 // Requests need one cycle to send an address
111 if (pkt->isRequest())
112 numCycles++;
113 else if (pkt->isResponse() || pkt->hasData()) {
114 // If a packet has data, it needs ceil(size/width) cycles to send it
115 // We're using the "adding instead of dividing" trick again here
116 if (pkt->hasData()) {
117 int dataSize = pkt->getSize();
118 for (int transmitted = 0; transmitted < dataSize;
119 transmitted += width) {
120 numCycles++;
121 }
122 } else {
123 // If the packet didn't have data, it must have been a response.
124 // Those use the bus for one cycle to send their data.
125 numCycles++;
126 }
127 }
128
129 // The first word will be delivered after the current tick, the delivery
130 // of the address if any, and one bus cycle to deliver the data
131 pkt->firstWordTime =
132 tickNextIdle +
133 pkt->isRequest() ? clock : 0 +
134 clock;
135
136 //Advance it numCycles bus cycles.
137 //XXX Should this use the repeated addition trick as well?
138 tickNextIdle += (numCycles * clock);
139 if (!busIdle.scheduled()) {
140 busIdle.schedule(tickNextIdle);
141 } else {
142 busIdle.reschedule(tickNextIdle);
143 }
144 DPRINTF(Bus, "The bus is now occupied from tick %d to %d\n",
145 curTick, tickNextIdle);
146
147 // The bus will become idle once the current packet is delivered.
148 pkt->finishTime = tickNextIdle;
149 }
150
151 /** Function called by the port when the bus is receiving a Timing
152 * transaction.*/
153 bool
154 Bus::recvTiming(PacketPtr pkt)
155 {
156 Port *port;
157 DPRINTF(Bus, "recvTiming: packet src %d dest %d addr 0x%x cmd %s\n",
158 pkt->getSrc(), pkt->getDest(), pkt->getAddr(), pkt->cmdString());
159
160 BusPort *pktPort;
161 if (pkt->getSrc() == defaultId)
162 pktPort = defaultPort;
163 else pktPort = interfaces[pkt->getSrc()];
164
165 // If the bus is busy, or other devices are in line ahead of the current
166 // one, put this device on the retry list.
167 if (tickNextIdle > curTick ||
168 (retryList.size() && (!inRetry || pktPort != retryList.front()))) {
169 addToRetryList(pktPort);
170 return false;
171 }
172
173 short dest = pkt->getDest();
174
175 // Make sure to clear the snoop commit flag so it doesn't think an
176 // access has been handled twice.
177 if (dest == Packet::Broadcast) {
178 port = findPort(pkt->getAddr(), pkt->getSrc());
179 pkt->flags &= ~SNOOP_COMMIT;
180 if (timingSnoop(pkt, port ? port : interfaces[pkt->getSrc()])) {
181 bool success;
182
183 pkt->flags |= SNOOP_COMMIT;
184 success = timingSnoop(pkt, port ? port : interfaces[pkt->getSrc()]);
185 assert(success);
186
187 if (pkt->flags & SATISFIED) {
188 //Cache-Cache transfer occuring
189 if (inRetry) {
190 retryList.front()->onRetryList(false);
191 retryList.pop_front();
192 inRetry = false;
193 }
194 occupyBus(pkt);
195 return true;
196 }
197 } else {
198 //Snoop didn't succeed
199 DPRINTF(Bus, "Adding a retry to RETRY list %d\n",
200 pktPort->getId());
201 addToRetryList(pktPort);
202 return false;
203 }
204 } else {
205 assert(dest >= 0 && dest < maxId);
206 assert(dest != pkt->getSrc()); // catch infinite loops
207 port = interfaces[dest];
208 }
209
210 occupyBus(pkt);
211
212 if (port) {
213 if (port->sendTiming(pkt)) {
214 // Packet was successfully sent. Return true.
215 // Also take care of retries
216 if (inRetry) {
217 DPRINTF(Bus, "Remove retry from list %d\n",
218 retryList.front()->getId());
219 retryList.front()->onRetryList(false);
220 retryList.pop_front();
221 inRetry = false;
222 }
223 return true;
224 }
225
226 // Packet not successfully sent. Leave or put it on the retry list.
227 DPRINTF(Bus, "Adding a retry to RETRY list %d\n",
228 pktPort->getId());
229 addToRetryList(pktPort);
230 return false;
231 }
232 else {
233 //Forwarding up from responder, just return true;
234 return true;
235 }
236 }
237
238 void
239 Bus::recvRetry(int id)
240 {
241 DPRINTF(Bus, "Received a retry\n");
242 // If there's anything waiting, and the bus isn't busy...
243 if (retryList.size() && curTick >= tickNextIdle) {
244 //retryingPort = retryList.front();
245 inRetry = true;
246 DPRINTF(Bus, "Sending a retry\n");
247 retryList.front()->sendRetry();
248 // If inRetry is still true, sendTiming wasn't called
249 if (inRetry)
250 {
251 retryList.front()->onRetryList(false);
252 retryList.pop_front();
253 inRetry = false;
254
255 //Bring tickNextIdle up to the present
256 while (tickNextIdle < curTick)
257 tickNextIdle += clock;
258
259 //Burn a cycle for the missed grant.
260 tickNextIdle += clock;
261
262 if (!busIdle.scheduled()) {
263 busIdle.schedule(tickNextIdle);
264 } else {
265 busIdle.reschedule(tickNextIdle);
266 }
267 }
268 }
269 //If we weren't able to drain before, we might be able to now.
270 if (drainEvent && retryList.size() == 0 && curTick >= tickNextIdle) {
271 drainEvent->process();
272 // Clear the drain event once we're done with it.
273 drainEvent = NULL;
274 }
275 }
276
277 Port *
278 Bus::findPort(Addr addr, int id)
279 {
280 /* An interval tree would be a better way to do this. --ali. */
281 int dest_id = -1;
282 AddrRangeIter iter;
283 range_map<Addr,int>::iterator i;
284
285 i = portMap.find(RangeSize(addr,1));
286 if (i != portMap.end())
287 dest_id = i->second;
288
289 // Check if this matches the default range
290 if (dest_id == -1) {
291 for (iter = defaultRange.begin(); iter != defaultRange.end(); iter++) {
292 if (*iter == addr) {
293 DPRINTF(Bus, " found addr %#llx on default\n", addr);
294 return defaultPort;
295 }
296 }
297
298 if (responderSet) {
299 panic("Unable to find destination for addr (user set default "
300 "responder): %#llx", addr);
301 } else {
302 DPRINTF(Bus, "Unable to find destination for addr: %#llx, will use "
303 "default port", addr);
304
305 return defaultPort;
306 }
307 }
308
309
310 // we shouldn't be sending this back to where it came from
311 // do the snoop access and then we should terminate
312 // the cyclical call.
313 if (dest_id == id)
314 return 0;
315
316 return interfaces[dest_id];
317 }
318
319 std::vector<int>
320 Bus::findSnoopPorts(Addr addr, int id)
321 {
322 int i = 0;
323 AddrRangeIter iter;
324 std::vector<int> ports;
325
326 while (i < portSnoopList.size())
327 {
328 if (portSnoopList[i].range == addr && portSnoopList[i].portId != id) {
329 //Careful to not overlap ranges
330 //or snoop will be called more than once on the port
331
332 //@todo Fix this hack because ranges are overlapping
333 //need to make sure we dont't create overlapping ranges
334 bool hack_overlap = false;
335 int size = ports.size();
336 for (int j=0; j < size; j++) {
337 if (ports[j] == portSnoopList[i].portId)
338 hack_overlap = true;
339 }
340
341 if (!hack_overlap)
342 ports.push_back(portSnoopList[i].portId);
343 // DPRINTF(Bus, " found snoop addr %#llx on device%d\n", addr,
344 // portSnoopList[i].portId);
345 }
346 i++;
347 }
348 return ports;
349 }
350
351 Tick
352 Bus::atomicSnoop(PacketPtr pkt, Port *responder)
353 {
354 std::vector<int> ports = findSnoopPorts(pkt->getAddr(), pkt->getSrc());
355 Tick response_time = 0;
356
357 while (!ports.empty())
358 {
359 if (interfaces[ports.back()] != responder) {
360 Tick response = interfaces[ports.back()]->sendAtomic(pkt);
361 if (response) {
362 assert(!response_time); //Multiple responders
363 response_time = response;
364 }
365 }
366 ports.pop_back();
367 }
368 return response_time;
369 }
370
371 void
372 Bus::functionalSnoop(PacketPtr pkt, Port *responder)
373 {
374 std::vector<int> ports = findSnoopPorts(pkt->getAddr(), pkt->getSrc());
375
376 //The packet may be changed by another bus on snoops, restore the id after each
377 int id = pkt->getSrc();
378 while (!ports.empty() && pkt->result != Packet::Success)
379 {
380 if (interfaces[ports.back()] != responder)
381 interfaces[ports.back()]->sendFunctional(pkt);
382 ports.pop_back();
383 pkt->setSrc(id);
384 }
385 }
386
387 bool
388 Bus::timingSnoop(PacketPtr pkt, Port* responder)
389 {
390 std::vector<int> ports = findSnoopPorts(pkt->getAddr(), pkt->getSrc());
391 bool success = true;
392
393 while (!ports.empty() && success)
394 {
395 if (interfaces[ports.back()] != responder) //Don't call if responder also, once will do
396 success = interfaces[ports.back()]->sendTiming(pkt);
397 ports.pop_back();
398 }
399
400 return success;
401 }
402
403
404 /** Function called by the port when the bus is receiving a Atomic
405 * transaction.*/
406 Tick
407 Bus::recvAtomic(PacketPtr pkt)
408 {
409 DPRINTF(Bus, "recvAtomic: packet src %d dest %d addr 0x%x cmd %s\n",
410 pkt->getSrc(), pkt->getDest(), pkt->getAddr(), pkt->cmdString());
411 assert(pkt->getDest() == Packet::Broadcast);
412 pkt->flags |= SNOOP_COMMIT;
413
414 // Assume one bus cycle in order to get through. This may have
415 // some clock skew issues yet again...
416 pkt->finishTime = curTick + clock;
417
418 Port *port = findPort(pkt->getAddr(), pkt->getSrc());
419 Tick snoopTime = atomicSnoop(pkt, port ? port : interfaces[pkt->getSrc()]);
420
421 if (snoopTime)
422 return snoopTime; //Snoop satisfies it
423 else if (port)
424 return port->sendAtomic(pkt);
425 else
426 return 0;
427 }
428
429 /** Function called by the port when the bus is receiving a Functional
430 * transaction.*/
431 void
432 Bus::recvFunctional(PacketPtr pkt)
433 {
434 DPRINTF(Bus, "recvFunctional: packet src %d dest %d addr 0x%x cmd %s\n",
435 pkt->getSrc(), pkt->getDest(), pkt->getAddr(), pkt->cmdString());
436 assert(pkt->getDest() == Packet::Broadcast);
437 pkt->flags |= SNOOP_COMMIT;
438
439 Port* port = findPort(pkt->getAddr(), pkt->getSrc());
440 functionalSnoop(pkt, port ? port : interfaces[pkt->getSrc()]);
441
442 // If the snooping found what we were looking for, we're done.
443 if (pkt->result != Packet::Success && port) {
444 port->sendFunctional(pkt);
445 }
446 }
447
448 /** Function called by the port when the bus is receiving a status change.*/
449 void
450 Bus::recvStatusChange(Port::Status status, int id)
451 {
452 AddrRangeList ranges;
453 AddrRangeList snoops;
454 AddrRangeIter iter;
455
456 assert(status == Port::RangeChange &&
457 "The other statuses need to be implemented.");
458
459 DPRINTF(BusAddrRanges, "received RangeChange from device id %d\n", id);
460
461 if (id == defaultId) {
462 defaultRange.clear();
463 // Only try to update these ranges if the user set a default responder.
464 if (responderSet) {
465 defaultPort->getPeerAddressRanges(ranges, snoops);
466 assert(snoops.size() == 0);
467 for(iter = ranges.begin(); iter != ranges.end(); iter++) {
468 defaultRange.push_back(*iter);
469 DPRINTF(BusAddrRanges, "Adding range %#llx - %#llx for default range\n",
470 iter->start, iter->end);
471 }
472 }
473 } else {
474
475 assert((id < maxId && id >= 0) || id == defaultId);
476 Port *port = interfaces[id];
477 range_map<Addr,int>::iterator portIter;
478 std::vector<DevMap>::iterator snoopIter;
479
480 // Clean out any previously existent ids
481 for (portIter = portMap.begin(); portIter != portMap.end(); ) {
482 if (portIter->second == id)
483 portMap.erase(portIter++);
484 else
485 portIter++;
486 }
487
488 for (snoopIter = portSnoopList.begin(); snoopIter != portSnoopList.end(); ) {
489 if (snoopIter->portId == id)
490 snoopIter = portSnoopList.erase(snoopIter);
491 else
492 snoopIter++;
493 }
494
495 port->getPeerAddressRanges(ranges, snoops);
496
497 for(iter = snoops.begin(); iter != snoops.end(); iter++) {
498 DevMap dm;
499 dm.portId = id;
500 dm.range = *iter;
501
502 //@todo, make sure we don't overlap ranges
503 DPRINTF(BusAddrRanges, "Adding snoop range %#llx - %#llx for id %d\n",
504 dm.range.start, dm.range.end, id);
505 portSnoopList.push_back(dm);
506 }
507
508 for(iter = ranges.begin(); iter != ranges.end(); iter++) {
509 DPRINTF(BusAddrRanges, "Adding range %#llx - %#llx for id %d\n",
510 iter->start, iter->end, id);
511 if (portMap.insert(*iter, id) == portMap.end())
512 panic("Two devices with same range\n");
513
514 }
515 }
516 DPRINTF(MMU, "port list has %d entries\n", portMap.size());
517
518 // tell all our peers that our address range has changed.
519 // Don't tell the device that caused this change, it already knows
520 m5::hash_map<short,BusPort*>::iterator intIter;
521
522 for (intIter = interfaces.begin(); intIter != interfaces.end(); intIter++)
523 if (intIter->first != id)
524 intIter->second->sendStatusChange(Port::RangeChange);
525
526 if (id != defaultId && defaultPort)
527 defaultPort->sendStatusChange(Port::RangeChange);
528 }
529
530 void
531 Bus::addressRanges(AddrRangeList &resp, AddrRangeList &snoop, int id)
532 {
533 std::vector<DevMap>::iterator snoopIter;
534 range_map<Addr,int>::iterator portIter;
535 AddrRangeIter dflt_iter;
536 bool subset;
537
538 resp.clear();
539 snoop.clear();
540
541 DPRINTF(BusAddrRanges, "received address range request, returning:\n");
542
543 for (dflt_iter = defaultRange.begin(); dflt_iter != defaultRange.end();
544 dflt_iter++) {
545 resp.push_back(*dflt_iter);
546 DPRINTF(BusAddrRanges, " -- Dflt: %#llx : %#llx\n",dflt_iter->start,
547 dflt_iter->end);
548 }
549 for (portIter = portMap.begin(); portIter != portMap.end(); portIter++) {
550 subset = false;
551 for (dflt_iter = defaultRange.begin(); dflt_iter != defaultRange.end();
552 dflt_iter++) {
553 if ((portIter->first.start < dflt_iter->start &&
554 portIter->first.end >= dflt_iter->start) ||
555 (portIter->first.start < dflt_iter->end &&
556 portIter->first.end >= dflt_iter->end))
557 fatal("Devices can not set ranges that itersect the default set\
558 but are not a subset of the default set.\n");
559 if (portIter->first.start >= dflt_iter->start &&
560 portIter->first.end <= dflt_iter->end) {
561 subset = true;
562 DPRINTF(BusAddrRanges, " -- %#llx : %#llx is a SUBSET\n",
563 portIter->first.start, portIter->first.end);
564 }
565 }
566 if (portIter->second != id && !subset) {
567 resp.push_back(portIter->first);
568 DPRINTF(BusAddrRanges, " -- %#llx : %#llx\n",
569 portIter->first.start, portIter->first.end);
570 }
571 }
572
573 for (snoopIter = portSnoopList.begin();
574 snoopIter != portSnoopList.end(); snoopIter++)
575 {
576 if (snoopIter->portId != id) {
577 snoop.push_back(snoopIter->range);
578 DPRINTF(BusAddrRanges, " -- Snoop: %#llx : %#llx\n",
579 snoopIter->range.start, snoopIter->range.end);
580 //@todo We need to properly insert snoop ranges
581 //not overlapping the ranges (multiple)
582 }
583 }
584 }
585
586 unsigned int
587 Bus::drain(Event * de)
588 {
589 //We should check that we're not "doing" anything, and that noone is
590 //waiting. We might be idle but have someone waiting if the device we
591 //contacted for a retry didn't actually retry.
592 if (curTick >= tickNextIdle && retryList.size() == 0) {
593 return 0;
594 } else {
595 drainEvent = de;
596 return 1;
597 }
598 }
599
600 BEGIN_DECLARE_SIM_OBJECT_PARAMS(Bus)
601
602 Param<int> bus_id;
603 Param<int> clock;
604 Param<int> width;
605 Param<bool> responder_set;
606
607 END_DECLARE_SIM_OBJECT_PARAMS(Bus)
608
609 BEGIN_INIT_SIM_OBJECT_PARAMS(Bus)
610 INIT_PARAM(bus_id, "a globally unique bus id"),
611 INIT_PARAM(clock, "bus clock speed"),
612 INIT_PARAM(width, "width of the bus (bits)"),
613 INIT_PARAM(responder_set, "Is a default responder set by the user")
614 END_INIT_SIM_OBJECT_PARAMS(Bus)
615
616 CREATE_SIM_OBJECT(Bus)
617 {
618 return new Bus(getInstanceName(), bus_id, clock, width, responder_set);
619 }
620
621 REGISTER_SIM_OBJECT("Bus", Bus)