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