style: [patch 1/22] use /r/3648/ to reorganize includes
[gem5.git] / src / mem / hmc_controller.cc
1 #include "mem/hmc_controller.hh"
2
3 #include "base/random.hh"
4 #include "debug/HMCController.hh"
5
6 HMCController::HMCController(const HMCControllerParams* p) :
7 NoncoherentXBar(p),
8 n_master_ports(p->port_master_connection_count),
9 rr_counter(0)
10 {
11 assert(p->port_slave_connection_count == 1);
12 }
13
14 HMCController*
15 HMCControllerParams::create()
16 {
17 return new HMCController(this);
18 }
19
20 // Since this module is a load distributor, all its master ports have the same
21 // range so we should keep only one of the ranges and ignore the others
22 void HMCController::recvRangeChange(PortID master_port_id)
23 {
24 if (master_port_id == 0)
25 {
26 gotAllAddrRanges = true;
27 BaseXBar::recvRangeChange(master_port_id);
28 }
29 else
30 gotAddrRanges[master_port_id] = true;
31 }
32
33 int HMCController::rotate_counter()
34 {
35 int current_value = rr_counter;
36 rr_counter++;
37 if (rr_counter == n_master_ports)
38 rr_counter = 0;
39 return current_value;
40 }
41
42 bool HMCController::recvTimingReq(PacketPtr pkt, PortID slave_port_id)
43 {
44 // determine the source port based on the id
45 SlavePort *src_port = slavePorts[slave_port_id];
46
47 // we should never see express snoops on a non-coherent component
48 assert(!pkt->isExpressSnoop());
49
50 // For now, this is a simple round robin counter, for distribution the
51 // load among the serial links
52 PortID master_port_id = rotate_counter();
53
54 // test if the layer should be considered occupied for the current
55 // port
56 if (!reqLayers[master_port_id]->tryTiming(src_port)) {
57 DPRINTF(HMCController, "recvTimingReq: src %s %s 0x%x BUSY\n",
58 src_port->name(), pkt->cmdString(), pkt->getAddr());
59 return false;
60 }
61
62 DPRINTF(HMCController, "recvTimingReq: src %s %s 0x%x\n",
63 src_port->name(), pkt->cmdString(), pkt->getAddr());
64
65 // store size and command as they might be modified when
66 // forwarding the packet
67 unsigned int pkt_size = pkt->hasData() ? pkt->getSize() : 0;
68 unsigned int pkt_cmd = pkt->cmdToIndex();
69
70 // store the old header delay so we can restore it if needed
71 Tick old_header_delay = pkt->headerDelay;
72
73 // a request sees the frontend and forward latency
74 Tick xbar_delay = (frontendLatency + forwardLatency) * clockPeriod();
75
76 // set the packet header and payload delay
77 calcPacketTiming(pkt, xbar_delay);
78
79 // determine how long to be layer is busy
80 Tick packetFinishTime = clockEdge(Cycles(1)) + pkt->payloadDelay;
81
82 // before forwarding the packet (and possibly altering it),
83 // remember if we are expecting a response
84 const bool expect_response = pkt->needsResponse() &&
85 !pkt->cacheResponding();
86
87 // since it is a normal request, attempt to send the packet
88 bool success = masterPorts[master_port_id]->sendTimingReq(pkt);
89
90 if (!success) {
91 DPRINTF(HMCController, "recvTimingReq: src %s %s 0x%x RETRY\n",
92 src_port->name(), pkt->cmdString(), pkt->getAddr());
93
94 // restore the header delay as it is additive
95 pkt->headerDelay = old_header_delay;
96
97 // occupy until the header is sent
98 reqLayers[master_port_id]->failedTiming(src_port,
99 clockEdge(Cycles(1)));
100
101 return false;
102 }
103
104 // remember where to route the response to
105 if (expect_response) {
106 assert(routeTo.find(pkt->req) == routeTo.end());
107 routeTo[pkt->req] = slave_port_id;
108 }
109
110 reqLayers[master_port_id]->succeededTiming(packetFinishTime);
111
112 // stats updates
113 pktCount[slave_port_id][master_port_id]++;
114 pktSize[slave_port_id][master_port_id] += pkt_size;
115 transDist[pkt_cmd]++;
116
117 return true;
118 }